Graphql Introspection in Axum with Basic Auth
Graphql Introspection in Axum with Basic Auth — how this specific combination creates or exposes the vulnerability
GraphQL introspection is a feature that allows clients to query the schema structure, types, and operations of a GraphQL endpoint. When enabled in production, introspection can expose detailed information about your API, including queries, mutations, and the data model. In Axum, a Rust web framework, GraphQL endpoints are typically implemented using libraries like async-graphql or juniper. If introspection is left enabled and the endpoint is protected only by Basic Auth, the combination creates a significant exposure.
Basic Auth transmits credentials in an encoded (not encrypted) string in the HTTP Authorization header. While Base64 is easily reversible, this does not provide confidentiality unless paired with TLS. An authenticated user with Basic Auth access could issue introspection queries to the GraphQL endpoint and retrieve the full schema. Even if Basic Auth limits who can reach the endpoint, the schema exposure can aid attackers in crafting more targeted attacks, such as identifying sensitive fields or operations for BOLA/IDOR or Property Authorization bypasses. middleBrick detects this as part of its Input Validation and Data Exposure checks, flagging active introspection when unauthenticated or low-privilege access to schema details is possible.
For example, a GraphQL endpoint in Axum using async-graphql might enable introspection by default during development. If the same code is promoted behind Basic Auth without explicitly disabling introspection, the endpoint remains capable of revealing its schema to any authenticated user. Attackers can leverage this information to map relationships and parameters, which middleBrick’s OpenAPI/Swagger spec analysis cross-references with runtime findings to highlight inconsistencies between documented and actual behavior.
middleBrick’s LLM/AI Security checks do not apply here, but its standard 12 parallel checks include scanning for excessive schema exposure. The scanner tests whether introspection queries return full type definitions, which can include sensitive business logic or data structures. This aligns with findings from the Authentication and Data Exposure checks, ensuring that the risk is surfaced with severity, remediation steps, and mapping to frameworks like OWASP API Top 10.
Basic Auth-Specific Remediation in Axum — concrete code fixes
To secure a GraphQL endpoint in Axum when using Basic Auth, you should explicitly disable introspection in production and ensure credentials are handled safely over TLS. Below are concrete code examples showing how to implement Basic Auth and disable introspection using async-graphql.
Example: Basic Auth middleware and GraphQL setup in Axum
use axum::{
async_trait,
extract::FromRequest,
http::{self, Request},
response::Response,
Extension, Router,
};
use async_graphql::{EmptyMutation, Object, Schema};
use async_graphql_axum::{GraphQLRequest, GraphQLResponse};
use std::net::SocketAddr;
use tower_http::services::ServeDir;
// Define a simple query
struct Query;
#[Object]
impl Query {
async fn hello(&self) -> &str {
"world"
}
}
type MySchema = Schema;
// Basic Auth extraction
struct AuthenticatedUser(String);
#[async_trait]
impl FromRequest for AuthenticatedUser
where
S: Send + Sync,
{
type Rejection = Response;
async fn from_request(req: Request, state: &S) -> Result {
let auth_header = req.headers().get(http::header::AUTHORIZATION);
match auth_header {
Some(header_value) => {
let header_str = header_value.to_str().unwrap_or("");
if header_str.starts_with("Basic ") {
// In production, validate credentials against a secure store
let decoded = base64::decode(&header_str[6..]).unwrap_or_default();
if decoded == b"valid_user:valid_pass" {
return Ok(AuthenticatedUser(String::from_utf8_lossy(&decoded).to_string()));
}
}
Err(axum::http::StatusCode::UNAUTHORIZED.into_response())
}
None => Err((axum::http::StatusCode::UNAUTHORIZED, "Missing authorization header")).into_response(),
}
}
}
async fn graphql_handler(
Extension(schema): Extension,
GraphQLRequest(request): GraphQLRequest,
) -> GraphQLResponse {
GraphQLResponse::from(schema.execute(request.into_inner()).await)
}
#[tokio::main]
async fn main() {
// Build schema with introspection disabled
let schema: MySchema = Schema::build(Query, EmptyMutation, ())
.enable_introspection(false) // Disable introspection in production
.finish();
let app = Router::new()
.route("/graphql", axum::routing::post(graphql_handler))
.layer(Extension(schema))
.nest_service("/", ServeDir::new("public"));
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
println!("Listening on {}", addr);
axum::Server::bind(&addr)
.serve(app.into_make_service())
.await
.unwrap();
}
Key remediation steps:
- Disable introspection explicitly via
.enable_introspection(false)in production builds. - Always serve over HTTPS to protect Basic Auth credentials in transit.
- Validate and store credentials securely; avoid hardcoding values as shown above in real services.
- Use Axum middleware to enforce authentication before requests reach the GraphQL handler.
middleBrick’s CLI can be used to verify that introspection is no longer exposed: middlebrick scan <url>. The dashboard and GitHub Action integrations allow you to track schema exposure over time and fail builds if risky configurations are detected.
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 |