shuvonsec/graphql-idor-scanner: The Differential Engine for GraphQL Identity Theft
Moving beyond status codes to detect cross-tenant data leakage through automated session comparison.
- The scanner identifies vulnerabilities by comparing successful data returns between two different user sessions rather than relying on HTTP status codes.
- Generic node resolvers often bypass the strict authorization logic applied to specific GraphQL queries.
- The tool operates without external dependencies to ensure immediate portability across restricted or ephemeral environments.
- Integrated modules test for authorization leaks across both GraphQL and legacy REST endpoints to prevent shadow API exploitation.
In the transition from REST to GraphQL, developers traded predictable, hierarchical URL paths for a "Global ID" black box. This architectural shift broke a fundamental assumption of traditional security scanning: that an unauthorized request would neatly return an HTTP 403 Forbidden or a 404 Not Found.
Modern APIs, particularly those employing GraphQL, often return a HTTP 200 OK even when an error occurs, burying the authorization failure deep within a JSON payload. Or worse, they return the requested data without checking who asked for it. This is the domain of the Insecure Direct Object Reference (IDOR), a vulnerability where an application fails to properly verify if the user requesting a resource is actually authorized to view it.
Generic infrastructure scanners are notoriously bad at finding these logic flaws because they lack context. They look for signature matches and status codes. The graphql-idor-scanner takes a different approach. It doesn't care if a request is syntactically valid or what HTTP status code is returned. It only cares about one thing: if the data returned to a stranger matches the data owned by the victim.
The Node IDOR: GraphQL’s Universal Backdoor
To understand why this tool exists, you have to understand the Relay specification and the concept of the Global ID (GID). In many complex GraphQL schemas, objects can be fetched via a generic node(id: ID!) interface. This is incredibly useful for client-side caching, allowing frameworks to request any object if they know its GID.
However, this creates a significant security blind spot. Developers often meticulously secure the specific queries—ensuring that query { invoice(id: 123) { amount } } checks if the user owns invoice 123. But they frequently forget to apply the same authorization logic to the generic node fetcher.
query {
node(id: "Z2lkOi8vYXBwL0ludm9pY2UvMTIz") {
... on Invoice {
amount
customerName
}
}
}
If the underlying resolver for the Invoice type doesn't independently verify ownership, an attacker can bypass the secured front door and simply ask the generic node query for the sensitive data. graphql-idor-scanner specifically targets this pattern. It automates the generation and manipulation of these Base64-encoded GIDs (like the one in the snippet above, which decodes to gid://app/Invoice/123) to systematically test for "Node IDORs."
Differential Analysis: The "Two-Key" System
The core innovation of the scanner is its dual-session architecture. It requires two distinct authentication tokens: Token A (belonging to the victim or resource owner) and Token B (belonging to the attacker). The script relies on a concept called differential analysis.
- Baseline Establishment: The scanner first executes a request using Token A to ensure the target resource is actually accessible and the query is well-formed.
- Unauthorized Replay: It then executes the exact same request, targeting the same resource ID, but using Token B.
- Data Comparison: The script compares the JSON response bodies. If Account B receives a populated data object that matches Account A's response—and no errors are present—the vulnerability is confirmed.
This method effectively eliminates the noise associated with traditional scanning. A 403 Forbidden is a "secure" state. A null response with an error message is a "secure" state. The scanner only flags a hit when the "mirror test" fails—when the attacker sees the exact same reflection as the victim.
Zero Dependencies, Maximum Portability
In an era of massive, containerized security suites, graphql-idor-scanner stands out for its austerity. It requires exactly zero external dependencies, relying entirely on the Python 3.10+ Standard Library. It uses urllib.request for network calls and the built-in json module for parsing.
This "Standard Library Only" philosophy makes the tool exceptionally portable. It is a utility designed for ephemeral environments—a locked-down VPS, a quick terminal session during a bug bounty engagement, or a CI/CD pipeline where installing third-party packages is restricted. It trades the exhaustive feature set of enterprise scanners for immediate, frictionless execution.
Bridging the Protocol Gap
Interestingly, the tool doesn't restrict itself purely to GraphQL. The author recognizes that modern applications often maintain a "shadow" REST API alongside their GraphQL implementation, exposing the same underlying data layers.
Among its 13 predefined test modules, the scanner includes checks for REST-based search index leakage and S3 Signed URL validation. This holistic approach acknowledges that if you can bypass authorization via a legacy REST endpoint, the meticulous security applied to the GraphQL schema is effectively moot.
| Feature | graphql-idor-scanner | Generic Infrastructure Scanners | Introspection Fuzzers |
|---|---|---|---|
| Primary Target | Business Logic / Authorization | Known CVEs / Misconfigurations | Denial of Service / Query Depth |
| Detection Method | Differential Data Comparison | Signature Matching / HTTP Codes | Payload Generation |
| Setup Complexity | Low (Zero dependencies) | High (Requires installation/config) | Medium (Requires schema parsing) |
| False Positive Rate | Extremely Low | High (Flags intended 403s) | High (Flags generic errors) |
By focusing narrowly on the logic of authorization rather than the mechanics of the protocol, graphql-idor-scanner provides a high-signal, low-noise approach to finding one of the most persistent and damaging vulnerabilities in modern web architecture.