Graphql Introspection in Actix with Api Keys
Graphql Introspection in Actix 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, introspection can expose sensitive implementation details that assist an attacker in crafting further attacks. In an Actix-web service, this typically manifests as an endpoint that responds to an introspection query even when API key validation is present, if the key check is applied only to selected routes or applied after the GraphQL handler has already resolved the request.
Consider an Actix-web service where API keys are validated via an extractor or middleware. If the GraphQL route handler does not gate introspection behind the same authorization logic, an unauthenticated attacker can send an introspection query and receive the full schema. The presence of API keys changes the threat model: it may stop anonymous reconnaissance, but if the key is not enforced at the GraphQL operation level, the attacker can still probe the API once a valid key is obtained through other means (e.g., leakage or shared credentials). This combination therefore does not eliminate introspection risk; it shifts the reliance from anonymous access to compromised credentials.
Moreover, introspection responses often include descriptions, deprecation status, and argument constraints that reveal business logic and data structures. In an Actix implementation that uses a wrapper to merge authentication and GraphQL resolution, failing to exclude introspection from key-protected paths—or failing to disable introspection in production—can lead to information disclosure as part of the unauthenticated attack surface tested by middleBrick. The scanner’s checks for Authentication and BOLA/IDOR in this context validate whether introspection is reachable without proper authorization, and whether API key enforcement is consistently applied across all GraphQL operations.
Api Keys-Specific Remediation in Actix — concrete code fixes
To secure GraphQL introspection in Actix while using API keys, ensure that introspection is disabled in production and that authorization is enforced before the GraphQL resolver runs. Below are concrete, syntactically correct examples demonstrating a secure Actix setup with API key validation and optional introspection control.
First, define a middleware or extractor that validates the API key. This example uses an extractor that checks a header value against a set of allowed keys:
use actix_web::{dev::ServiceRequest, Error, HttpMessage};
use actix_web::http::header::HeaderValue;
use actix_web::web::Data;
use std::collections::HashSet;
struct ApiKey(String);
async fn validate_key(req: ServiceRequest) -> Result {
let keys: Data> = req.app_data().unwrap();
let header = req.headers().get("x-api-key")
.and_then(|v| v.to_str().ok())
.map(String::from);
match header {
Some(k) if keys.contains(&k) => Ok(req),
_ => Err(actix_web::error::ErrorUnauthorized("Invalid API key")),
}
}
// In main or app configuration:
// let mut allowed = HashSet::new();
// allowed.insert("your-secret-key".to_string());
// let keys = Data::new(allowed);"
Second, configure your GraphQL route to require the key and disable introspection when not in development. Using the actix_web_graphql crate, you can conditionally turn off introspection:
use actix_web_graphql::{GraphQLRequest, GraphQLResponse};
use actix_web::{web, App, HttpResponse, HttpServer};
async fn graphql_route(
req: web::Json,
gql_config: web::Data,
) -> GraphQLResponse {
// gql_config should be built with introspection disabled in production
gql_config.execute(&req.query).await
}
// When building the config:
// let config = GraphQLConfig::new(schema)
// .introspection(false) // disable introspection in production
// .data(/* your data */);"
Finally, wire the validation into the Actix app so that the GraphQL route is protected:
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let mut allowed = HashSet::new();
allowed.insert("your-secret-key".to_string());
let keys = web::Data::new(allowed);
HttpServer::new(move || {
App::new()
.app_data(keys.clone())
.wrap_fn(|req, srv| {
let keys = req.app_data::>>().unwrap();
validate_key(req).map_or_else(
|e| futures::future::err(e),
|req| {
srv.call(req).map(|res| res.map_err(|e| e.into()))
},
)
})
.service(
web::resource("/graphql")
.route(web::post().to(graphql_route))
)
})
.bind("127.0.0.1:8080")?
.run()
.await
}
These examples illustrate how to combine API key validation with controlled introspection in Actix. By disabling introspection in production and ensuring the key check is applied consistently, you reduce the risk of schema exposure while maintaining a functional GraphQL endpoint.
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 |