Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save BuffaloWill/a50c7fe465b98884ed42e1a94aaea56c to your computer and use it in GitHub Desktop.
Save BuffaloWill/a50c7fe465b98884ed42e1a94aaea56c to your computer and use it in GitHub Desktop.
Notes from GraphQL Exploitation: Secondary Context Attacks and Business Logic Vulnerabilities

Summary

This document has references and notes from the OWASP Global AppSec 2024 talk; "GraphQL Exploitation: Secondary Context Attacks and Business Logic Vulnerabilities".

Author

Secondary Context Attacks References

Tool References

Defense References

Bambadas Code

GraphQL Operation Name in URL

return requestResponse.request().parameterValue("operationName", HttpParameterType.URL);

Show Content Type in Table Column:

return requestResponse.request().headerValue("Content-Type");

Highlight a request if it has ID! in it. This gets kind of janky trying to pull the mutation or query name:

    // Get the request body
    String body = requestResponse.request().bodyToString();
    if (body.contains("ID!") || body.contains("String!")) {
        requestResponse.annotations().setHighlightColor(HighlightColor.RED);
    }
    // Check for POST requests (most common for GraphQL)
    if (requestResponse.request().method().equals("POST")) {
        try {
            // Pattern to match mutations, including inline definitions and input parameters
            Pattern mutationPattern = Pattern.compile("\"mutation\"\\s*:\\s*\"\\s*(mutation\\s+(\\w+)(\\([^)]*\\))?|mutation)\\s*\\{|\"mutation\"\\s*:\\s*\"mutation\\s+(\\w+)(\\([^)]*\\))?");
            Matcher mutationMatcher = mutationPattern.matcher(body);
            
            if (mutationMatcher.find()) {
                String operationName = mutationMatcher.group(2) != null ? mutationMatcher.group(2) : mutationMatcher.group(4);
                String inputs = mutationMatcher.group(3) != null ? mutationMatcher.group(3) : 
                                (mutationMatcher.group(5) != null ? mutationMatcher.group(5) : "");
                if (operationName != null && !operationName.isEmpty()) {
                    return "mutation " + operationName + inputs;
                } else {
                    return "mutation (unnamed)" + inputs;
                }
            }
            
            // If no mutation found, check for queries
            Pattern queryPattern = Pattern.compile("\"query\"\\s*:\\s*\"\\s*(query\\s+(\\w+)(\\([^)]*\\))?|query)\\s*\\{|\"query\"\\s*:\\s*\"query\\s+(\\w+)(\\([^)]*\\))?");
            Matcher queryMatcher = queryPattern.matcher(body);
            
            if (queryMatcher.find()) {
                String operationName = queryMatcher.group(2) != null ? queryMatcher.group(2) : queryMatcher.group(4);
                String inputs = queryMatcher.group(3) != null ? queryMatcher.group(3) : 
                                (queryMatcher.group(5) != null ? queryMatcher.group(5) : "");
                if (operationName != null && !operationName.isEmpty()) {
                    return "query " + operationName + inputs;
                } else {
                    return "query (unnamed)" + inputs;
                }
            }
        } catch (Exception e) {
            // If parsing fails, try to find GraphQL operations in raw body
            Pattern rawPattern = Pattern.compile("(mutation|query)\\s+(\\w+)(\\([^)]*\\))?");
            Matcher rawMatcher = rawPattern.matcher(body);
            if (rawMatcher.find()) {
                String inputs = rawMatcher.group(3) != null ? rawMatcher.group(3) : "";
                return rawMatcher.group(1) + " " + rawMatcher.group(2) + inputs;
            } else {
                // Check for unnamed operations
                Pattern unnamedPattern = Pattern.compile("(mutation|query)\\s*(\\([^)]*\\))?\\s*\\{");
                Matcher unnamedMatcher = unnamedPattern.matcher(body);
                if (unnamedMatcher.find()) {
                    String inputs = unnamedMatcher.group(2) != null ? unnamedMatcher.group(2) : "";
                    return unnamedMatcher.group(1) + " (unnamed)" + inputs;
                }
            }
        }
    } 
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment