Graphql Introspection in Axum with Api Keys
Graphql Introspection in Axum 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. When enabled in production, it can expose implementation details that assist attackers in crafting injection or privilege escalation attacks. In an Axum-based Rust service, introspection is typically controlled by the GraphQL library configuration. If introspection is left enabled and the endpoint is protected only by API keys, the exposure surface changes in a meaningful way.
API keys are a common authentication mechanism where a secret string is passed in headers or query parameters to identify the caller. In Axum, this is often implemented via middleware that checks for a key before allowing the request to proceed. When GraphQL introspection is allowed alongside API key protection, an attacker who does not yet have a valid key might still be able to perform introspection if the middleware applies authentication too late in the request pipeline. For example, if the GraphQL handler is invoked before the key validation middleware runs, or if the introspection resolver is not explicitly guarded, the schema can be leaked without proper authorization checks.
Consider a typical Axum setup where routes are defined and middleware is applied. If the GraphQL route uses a wrapper that does not correctly enforce authentication before invoking the GraphQL introspection resolver, the introspection query can succeed regardless of the key’s validity or presence. This effectively turns the API key into a weak gatekeeper: the key may be required for normal operations, but introspection bypasses its intent. Attackers can use introspection to discover query names, filter patterns, and relationships, which can then be used to probe for IDOR, BOLA, or other logic flaws.
Furthermore, if the API key is passed in a predictable header or query parameter and introspection is enabled, automated scanners can correlate the presence of a valid key with schema exposure. This can lead to a clearer picture of how authorization is applied across different fields and types in the schema, increasing the risk of privilege escalation or data exposure. In a black-box scan, an unauthenticated introspection query against an Axum endpoint with API key protection may still succeed if the middleware configuration does not short-circuit the GraphQL execution on missing or invalid keys.
To detect this using middleBrick, a scan would include checks for Authentication and BOLA/IDOR alongside GraphQL-specific probes. The scanner validates whether introspection can be executed without valid credentials and whether the API key enforcement is consistently applied across all GraphQL operations. Remediation guidance focuses on ensuring introspection is disabled in production and that authentication is enforced before any GraphQL resolver is invoked.
Api Keys-Specific Remediation in Axum — concrete code fixes
Securing GraphQL introspection in Axum with API keys requires precise control over middleware ordering and explicit disabling of introspection in production. Below are concrete, working examples that demonstrate how to implement this correctly.
Example 1: Disabling introspection via schema building
When creating your GraphQL schema, disable introspection by setting introspection_limit and ensuring the schema is built without introspection support. This prevents introspection regardless of route configuration.
use async_graphql::{Schema, EmptySubscription, Object};
use async_graphql::http::{GraphiQLSource, GraphQLRequest};
use async_graphql::parser::types::Schema as GraphQLSchema;
struct Query;
#[Object]
impl Query {
async fn hello(&self) -> &str {
"world"
}
}
let schema = Schema::build(Query, EmptySubscription, EmptySubscription)
.introspection_limit(async_graphql::http::IntrospectionLimit::Disable)
.finish();
Example 2: Axum middleware enforcing API keys before GraphQL handler
This example shows an Axum route where API key validation occurs before the GraphQL handler is invoked. The middleware returns 401 if the key is missing or invalid, ensuring introspection cannot bypass the check.
use axum::{Router, routing::post, extract::Request, http::StatusCode};
use axum::middleware::Next;
use std::sync::Arc;
async fn api_key_middleware(
request: Request,
next: Next,
) -> Result {
let valid = validate_api_key(request.headers());
if !valid {
return Err((StatusCode::UNAUTHORIZED, "Invalid API key".to_string()));
}
Ok(next.run(request).await)
}
fn validate_api_key(headers: &axum::http::HeaderMap) -> bool {
const EXPECTED: &str = "secret_key_123";
headers.get("X-API-Key")
.and_then(|v| v.to_str().ok())
.map(|s| s == EXPECTED)
.unwrap_or(false)
}
let app = Router::new()
.route("/graphql", post(graphql_handler))
.layer(axum::middleware::from_fn(api_key_middleware));
Example 3: Explicitly rejecting introspection in the GraphQL handler
Even with schema-level disabling, you can add runtime checks inside your handler to reject introspection queries when API keys are used. This provides defense-in-depth.
use async_graphql::Request;
async fn graphql_handler(
axum::extract::State(schema): axum::extract::State>>,
axum::extract::Header(axum::http::header::AUTHORIZATION): Option,
request: Request,
) -> impl IntoResponse {
if request.is_introspection() {
return Err("Introspection is disabled") as &str;
}
let response = schema.execute(request).await;
// return response
}
These examples ensure that API keys are validated early and that introspection is disabled or explicitly rejected. middleBrick scans can verify that these protections are present by checking for Authentication and GraphQL-specific findings.
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 |