Graphql Introspection in Feathersjs with Firestore
Graphql Introspection in Feathersjs 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 invaluable for development tools but can expose sensitive design details in production. When using FeathersJS with a Firestore backend, introspection can reveal the structure of your service definitions, field types, and relationships that are otherwise abstracted by the ORM-like layer. This becomes a security concern when the introspection query is allowed through to the Firestore layer without restriction, potentially exposing data model details that aid an attacker in crafting targeted BOLA/IDOR or Property Authorization attacks.
In a FeathersJS application, GraphQL schemas are often defined as part of the service configuration. If introspection is enabled and the GraphQL endpoint is publicly reachable, an attacker can send an introspection query like { __schema { queryType { name } types { name fields { name } } } } and receive a full description of the available queries and mutations. Because FeathersJS may directly map these operations to Firestore collections and documents, the returned schema can hint at collection names, document IDs, and field hierarchies that map 1-to-1 with your Firestore database structure. This mapping is especially sensitive when Firestore security rules are misconfigured or when combined with weak authentication checks, as the exposed schema can guide an attacker toward endpoints where BOLA/IDOR vulnerabilities exist.
Additionally, because FeathersJS typically uses a service-oriented architecture, each GraphQL type often corresponds to a Firestore collection or a subcollection. Introspection can expose nested types and relations, revealing how documents are linked — for example, a posts type referencing a userId field that maps to a Firestore document in a users collection. If the API also lacks proper rate limiting or authentication on the GraphQL endpoint, this information can be leveraged in conjunction with other checks such as Unauthenticated LLM Endpoint detection or Property Authorization weaknesses. MiddleBrick scans detect such exposure as part of its 12 parallel security checks, highlighting GraphQL introspection as a finding when it reveals actionable attack surfaces in the context of Firestore-backed FeathersJS services.
Firestore-Specific Remediation in Feathersjs — concrete code fixes
To secure a FeathersJS application using Firestore, you should disable or guard GraphQL introspection in production and enforce strict input validation and authorization at the service layer. Below are concrete code examples that demonstrate how to configure a FeathersJS GraphQL service with Firestore while mitigating introspection-related risks.
1. Disable introspection in production
When initializing the GraphQL server, set introspection to false in production environments. This prevents external clients from querying the schema.
const { GraphQLServer } = require('graphql-yoga');
const feathers = require('@feathersjs/feathers');
const graphql = require('@feathersjs/graphql');
const app = feathers();
const server = new GraphQLServer({
typeDefs: './src/schema.graphql',
resolvers: require('./src/resolvers'),
introspection: process.env.NODE_ENV !== 'production', // disable in prod
});
app.configure(graphql({ server }));
2. Secure Firestore service definitions
Define your FeathersJS Firestore service with explicit filtering and validation to ensure that only intended fields are exposed and that document access is restricted.
const { Service } = require('feathers-firebase');
const admin = require('firebase-admin');
admin.initializeApp({
credential: admin.credential.applicationDefault(),
});
class FirestorePostsService extends Service {
async get(id, params) {
const doc = await admin.firestore().collection('posts').doc(id).get();
if (!doc.exists) {
throw new Error('Document not found');
}
// Ensure the requesting user has access, if applicable
if (params.user && params.user.uid !== doc.data().userId) {
throw new Error('Unauthorized');
}
return doc.data();
}
}
app.use('/posts', new FirestorePostsService({
Model: admin.firestore(),
collection: 'posts',
paginate: { default: 10, max: 50 },
}));
3. Apply field-level authorization
Use FeathersJS hooks to strip sensitive fields before returning data to the client, ensuring that even if introspection reveals a field, it cannot be accessed without proper permissions.
const { iff, isProvider } = require('feathers-hooks-common');
app.service('posts').hooks({
after: {
all: [
iff(isProvider('external'), (context) => {
const { userId } = context.result;
delete context.data.passwordHash;
if (context.result.__v) delete context.result.__v;
// Ensure only safe fields are returned
return context;
}),
],
},
});
4. Validate and limit GraphQL queries
Use schema directives or query whitelisting to prevent overly broad introspection or deeply nested queries that could traverse Firestore document trees unexpectedly.
// Example schema directive to block introspection in production
const { makeExecutableSchema } = require('@graphql-tools/schema');
const schema = makeExecutableSchema({
typeDefs,
resolvers,
directiveResolvers: {
disableInProduction: {
Field: (_, args, ctx, info) => {
if (process.env.NODE_ENV !== 'production' && info.schemaIntrospection) {
throw new Error('Introspection is disabled in production');
}
},
},
},
});
By combining environment-aware introspection settings, strict Firestore document access patterns, and FeathersJS hooks, you reduce the attack surface exposed through GraphQL while still leveraging the flexibility of a NoSQL backend.
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 |