Graphql Introspection in Axum with Firestore
Graphql Introspection in Axum with Firestore — how this specific combination creates or exposes the vulnerability
GraphQL introspection is a feature that allows clients to query the schema for type information, which is valuable during development but can expose sensitive design details in production. When using Axum with a Firestore backend, introspection can reveal collection names, field structures, and query patterns that map closely to your Firestore instance. This becomes a risk when the GraphQL endpoint is publicly reachable and introspection is not disabled, because an attacker can programmatically discover the shape of your data model without authentication.
In Axum, GraphQL routes are typically added via crates like async-graphql or juniper. If the GraphQL schema is built directly from Firestore document structures—such as mapping Firestore documents to Rust structs with serde—introspection responses may inadvertently mirror Firestore collection and field names. For example, a Firestore collection named user_profiles might appear as a GraphQL type UserProfile, and introspection will list related queries and fields. This mapping can help an attacker refine injection or enumeration attacks, especially if combined with other findings like missing rate limiting or weak input validation.
Because middleBrick checks 12 security categories in parallel, including Input Validation and Property Authorization, it can detect when introspection is enabled on a GraphQL endpoint that also interacts with Firestore. The scanner does not rely on internal architecture, but it observes that the GraphQL response includes a __schema query capability when it should not in production. This finding appears alongside other checks such as Authentication and BOLA/IDOR, helping to contextualize risk. For instance, if introspection is open and Firestore rules are misconfigured, an attacker might use schema details to craft queries that bypass authorization at the property level.
Remediation guidance provided by middleBrick focuses on server-side controls. You should disable introspection in production environments and ensure that only necessary types and fields are exposed through your GraphQL schema. Combine this with strong Firestore security rules and robust input validation to reduce the attack surface. middleBrick’s report will list this as a finding with severity and actionable steps rather than attempting to fix the configuration itself.
Firestore-Specific Remediation in Axum — concrete code fixes
To secure a GraphQL endpoint in Axum that uses Firestore, you should disable introspection and carefully design your schema exposure. Below are code examples showing how to configure async-graphql to disable introspection and how to structure Firestore document mappings safely.
Disabling Introspection in async-graphql
Create your schema with introspection disabled, and avoid exposing raw Firestore document types directly.
use async_graphql::{Schema, EmptySubscription, parser::ParseConfig};
use async_graphql::http::{GraphiQLSource, GraphQLPlaygroundSource};
use async_graphql_actix_web::GraphQLRequest;
struct Query;
#[async_graphql::Object]
impl Query {
async fn health(&self) -> String {
"ok".to_string()
}
}
// Disable introspection and strict mode for production safety
let schema = Schema::build(Query, EmptySubscription, EmptySubscription)
.parse_options(ParseOptions {
allow_introspection: false,
..ParseOptions::default()
})
.finish();
// In your Axum route handler
async fn graphql_handler(
schema: web::Data>,
req: GraphQLRequest,
) -> GraphQLResponse {
schema.execute(req.into_inner()).await.into()
}
Safe Firestore Integration without Exposing Internal Structure
Map Firestore documents to dedicated output types rather than exposing collections directly. This limits what introspection would reveal even if it were enabled during development.
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, SimpleObject)]
struct UserProfileOutput {
id: String,
display_name: String,
email: String,
}
#[async_graphql::Object]
impl Query {
async fn get_user_profile(&self, user_id: String) -> Option {
let db = firestore::FirestoreDb::new("my-project").await.unwrap();
let doc_ref = db.doc(&format!("user_profiles/{}", user_id));
let snapshot = doc_ref.get().await.ok()?;
let data: serde_json::Value = snapshot.get("data")?;
serde_json::from_value(data).ok()
}
}
Axum Middleware and Route Protection
Use Axum middleware to block introspection queries at the HTTP layer when not in development. This complements the schema-level configuration.
use axum::{routing::post, Router};
fn app_routes(schema: Schema) -> Router {
Router::new()
.route("/graphql", post(graphql_handler))
.with_state(web::Data::new(schema))
}
These steps reduce the visibility of your Firestore-backed GraphQL API. middleBrick will note whether introspection is disabled in its scan report and will not flag it as a finding when properly configured.
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 |