Graphql Introspection in Fastapi with Api Keys
Graphql Introspection in Fastapi with Api Keys — how this specific combination creates or exposes the vulnerability
GraphQL introspection is a feature that allows clients to query the schema of a GraphQL service, including types, queries, and mutations. In FastAPI, when GraphQL endpoints are exposed without restricting introspection, any unauthenticated or poorly authenticated client can retrieve the full schema. This behavior becomes a security risk when API keys are used for authentication but are not properly validated before the introspection query reaches the GraphQL layer.
When API keys are accepted but not rigorously enforced across all operations, introspection can remain enabled for keyed requests. An attacker who discovers or guesses a valid API key can issue an introspection query to map the API surface, revealing sensitive types, queries, and potential entry points for further attacks such as BOLA or IDOR. Even if the API key is intended to limit access to certain resources, introspection can expose fields and relationships that should be hidden, effectively bypassing intended visibility controls.
In FastAPI, this often occurs when GraphQL routes are mounted without a pre-execution check that blocks introspection based on authentication context. The API key may validate identity, but if the GraphQL resolver or schema introspection is not explicitly disabled for keyed requests, the endpoint remains informative to an attacker. This is especially relevant in unauthenticated attack surface testing, where middleBrick runs checks such as Authentication and BOLA/IDOR in parallel, detecting whether introspection is allowed alongside key-based access controls.
Real-world examples include schemas exposing internal data models like User, Account, or Payment, which can hint at internal architecture or data storage patterns. If introspection is allowed, attackers can combine schema knowledge with automated probing to craft targeted queries, increasing the effectiveness of other checks such as Property Authorization and Input Validation.
middleBrick identifies this risk by testing the unauthenticated attack surface and correlating findings with authentication mechanisms. Reports highlight whether introspection is permitted alongside API key validation, providing severity-ranked findings and remediation guidance mapped to frameworks such as OWASP API Top 10 and SOC2 controls.
Api Keys-Specific Remediation in Fastapi — concrete code fixes
To secure GraphQL introspection in FastAPI when using API keys, you must explicitly disable introspection for requests that include API key authentication or restrict introspection based on key validity and scope. Below are concrete code examples demonstrating how to implement this.
Example 1: Disable introspection for all keyed requests
Use a custom introspection_resolver that returns None when an API key is present, effectively disabling introspection for authenticated or keyed clients.
from fastapi import FastAPI, Depends, HTTPException, Security
from starlette.graphql import GraphQLRoute
from graphene import ObjectType, String, Schema
from starlette.requests import Request
app = FastAPI()
class Query(ObjectType):
hello = String(name=String(default_value="world"))
def resolve_hello(self, info, name):
return f"Hello {name}"
# Dependency that extracts and validates API key
def get_api_key(request: Request):
api_key = request.headers.get("X-API-Key")
if not api_key or api_key != "your-secure-key":
raise HTTPException(status_code=403, detail="Invalid or missing API key")
return api_key
# Disable introspection when API key is used
introspection_resolver = lambda *_: None
schema = Schema(query=Query, introspection=introspection_resolver)
@app.route("/graphql", methods=["POST", "GET"])
def graphql_endpoint(request: Request, api_key: str = Security(get_api_key)):
from starlette.graphql import run_graphql_request
return run_graphql_request(
request=request,
schema=schema,
debug=True,
)
Example 2: Conditionally allow introspection based on key scope
Allow introspection only for a special key or role, ensuring that production keys do not expose schema details.
from fastapi import FastAPI, Security, HTTPException
from starlette.graphql import GraphQLRoute
from graphene import ObjectType, String, Schema
from starlette.requests import Request
app = FastAPI()
class Query(ObjectType):
public_data = String()
def resolve_public_data(self, info):
return "public"
ALLOW_INTROSPECTION_KEYS = {"debug-key-123"}
def get_api_key(request: Request):
key = request.headers.get("X-API-Key")
if not key:
raise HTTPException(status_code=403, detail="API key required")
return key
# Custom resolver that checks key permissions
def safe_introspection_resolver(root, info):
api_key = info.context.headers.get("X-API-Key", "")
if api_key in ALLOW_INTROSPECTION_KEYS:
return None # Allow introspection
return None # Always disable introspection for safety; adjust as needed
schema = Schema(query=Query, introspection=safe_introspection_resolver)
@app.get("/graphql")
def graphql(request: Request, api_key: str = Security(get_api_key)):
from starlette.graphql import run_graphql_request
return run_graphql_request(request=request, schema=schema, debug=True)
General remediation practices
- Ensure introspection is disabled by default in production builds, regardless of authentication.
- Validate API keys before allowing any GraphQL execution, and treat keys as credentials.
- Combine these measures with checks for BOLA/IDOR and Rate Limiting to reduce the attack surface.
- Use middleware or route dependencies to enforce key presence and correctness before the request reaches the GraphQL layer.
These fixes align with guidance provided by tools like middleBrick, which can detect whether introspection is exposed alongside API key usage and provide prioritized remediation steps.
Related CWEs: dataExposure
| CWE ID | Name | Severity |
|---|---|---|
| CWE-200 | Exposure of Sensitive Information | HIGH |
| CWE-209 | Error Information Disclosure | MEDIUM |
| CWE-213 | Exposure of Sensitive Information Due to Incompatible Policies | HIGH |
| CWE-215 | Insertion of Sensitive Information Into Debugging Code | MEDIUM |
| CWE-312 | Cleartext Storage of Sensitive Information | HIGH |
| CWE-359 | Exposure of Private Personal Information (PII) | HIGH |
| CWE-522 | Insufficiently Protected Credentials | CRITICAL |
| CWE-532 | Insertion of Sensitive Information into Log File | MEDIUM |
| CWE-538 | Insertion of Sensitive Information into Externally-Accessible File | HIGH |
| CWE-540 | Inclusion of Sensitive Information in Source Code | HIGH |