Graphql Introspection in Feathersjs
How Graphql Introspection Manifests in Feathersjs
Graphql Introspection is a feature that allows clients to query the schema of a GraphQL API to discover available types, queries, mutations, and fields. While this is useful for development and tooling, it can expose sensitive information in production. In Feathersjs, introspection manifests through the default GraphQL configuration and the way Feathersjs exposes service schemas.
Feathersjs applications typically set up GraphQL using the @feathersjs/graphql module. By default, introspection is enabled, allowing any client to retrieve the complete schema. This becomes problematic when your Feathersjs API exposes internal service structures, database models, or business logic that shouldn't be public knowledge.
The vulnerability appears in several ways in Feathersjs applications:
- Default schema exposure: Feathersjs automatically generates GraphQL schemas from your services, including field names, types, and relationships that might reveal implementation details
- Service metadata leakage: Internal service configurations, database table names, and field constraints become visible through introspection queries
- Business logic exposure: Custom resolvers and computed fields that contain sensitive business logic can be discovered
- Authentication bypass patterns: Attackers can map out which queries and mutations exist before attempting to bypass authentication
A typical Feathersjs introspection attack might look like this:
query IntrospectionQuery {
__schema {
types {
name
kind
description
}
queryType {
name
fields {
name
description
type {
name
}
}
}
}
}
When executed against a Feathersjs GraphQL endpoint, this query returns comprehensive information about all services, their methods, and data structures. For example, if you have a users service with authentication logic, an attacker can discover that a login mutation exists and craft targeted attacks against it.
Feathersjs's schema-first approach means that even custom type definitions in your typeDefs files are exposed. If you've defined internal-only types or enums that represent system states, these become visible to anyone who can reach your GraphQL endpoint.
Feathersjs-Specific Detection
Detecting GraphQL introspection vulnerabilities in Feathersjs requires both manual testing and automated scanning. Here are Feathersjs-specific approaches to identify this issue:
Manual Detection Methods
First, examine your Feathersjs GraphQL setup. In your service initialization, check if you're using the default configuration:
const { graphql } = require('@feathersjs/graphql');
const { schema } = require('./schema');
app.use('/graphql', graphql({ schema, }));
The absence of an introspection option means it's enabled by default. You can test this by sending a simple introspection query to your Feathersjs endpoint:
curl -X POST http://localhost:3030/graphql \
-H "Content-Type: application/json" \
-d '{"query": "{\n __schema {\n types { name }\n }\n}"}'
If you receive a response with type information, introspection is enabled.
Using middleBrick for Automated Detection
middleBrick's GraphQL security scanner specifically detects introspection vulnerabilities in Feathersjs applications. The scanner sends standard introspection queries and analyzes the response for exposed schema information. Here's how to scan a Feathersjs API:
npx middlebrick scan http://your-feathersjs-app.com/graphql
The scan tests for:
- Whether introspection queries succeed without authentication
- The completeness of schema information returned
- Exposure of internal service names and field structures
- Presence of sensitive type definitions
middleBrick provides a security score and specific findings about GraphQL introspection, including whether your Feathersjs endpoint exposes more information than necessary for production use.
Code Review Indicators
During code review of Feathersjs applications, look for these patterns that indicate introspection exposure:
// Vulnerable: Default configuration
app.use('/graphql', graphql({ schema }));
// Better: Explicitly disable in production
const graphqlConfig = {
schema,
introspection: process.env.NODE_ENV === 'development'
};
app.use('/graphql', graphql(graphqlConfig));
Also check for the use of makeExecutableSchema from graphql-tools without proper security configurations, and verify that your Feathersjs services don't expose internal-only types through the GraphQL interface.
Feathersjs-Specific Remediation
Remediating GraphQL introspection vulnerabilities in Feathersjs involves both configuration changes and architectural considerations. Here are Feathersjs-specific solutions:
Disable Introspection in Production
The most straightforward fix is to disable introspection when your Feathersjs app runs in production:
const { graphql } = require('@feathersjs/graphql');
const { schema } = require('./schema');
const graphqlConfig = {
schema,
introspection: process.env.NODE_ENV === 'development'
};
module.exports = app => {
app.use('/graphql', graphql(graphqlConfig));
};
This approach allows introspection during development while protecting your production API.
Schema Filtering for Feathersjs
For more granular control, implement schema filtering in your Feathersjs GraphQL setup. This allows you to selectively expose parts of your schema:
const { graphql } = require('@feathersjs/graphql');
const { makeExecutableSchema } = require('@graphql-tools/schema');
const { filterSchema } = require('@graphql-tools/schema');
const originalSchema = makeExecutableSchema({
typeDefs: fs.readFileSync('./schema.graphql', 'utf8'),
resolvers: yourResolvers
});
const filteredSchema = filterSchema({
schema: originalSchema,
filterIntrospection: process.env.NODE_ENV === 'production',
ignore: ['Query', 'Mutation'] // Keep root types
});
const graphqlConfig = {
schema: filteredSchema,
introspection: process.env.NODE_ENV === 'development'
};
module.exports = app => {
app.use('/graphql', graphql(graphqlConfig));
};
Feathersjs Service-Level Protection
Combine introspection protection with Feathersjs's built-in authentication and authorization. Modify your service setup to include GraphQL security:
const { authenticate } = require('@feathersjs/authentication');
const { graphql } = require('@feathersjs/graphql');
const { schema } = require('./schema');
module.exports = app => {
const graphqlConfig = {
schema,
introspection: process.env.NODE_ENV === 'development'
};
const graphqlService = graphql(graphqlConfig);
// Apply authentication to GraphQL endpoint
app.use('/graphql', authenticate('jwt'), graphqlService);
};
Custom Introspection Handler
For advanced scenarios, implement a custom introspection handler that returns limited information:
const { graphql } = require('@feathersjs/graphql');
const { schema } = require('./schema');
async function introspectionHandler(request, response) {
if (process.env.NODE_ENV === 'production') {
return response.status(403).json({
error: 'Introspection disabled in production'
});
}
// Allow introspection in development
return graphql({ schema })(request, response);
}
module.exports = app => {
app.use('/graphql', (req, res, next) => {
if (req.method === 'POST' && req.body && req.body.query) {
const firstLine = req.body.query.split('\n')[0];
if (firstLine.includes('__schema') || firstLine.includes('__type')) {
return introspectionHandler(req, res);
}
}
return graphql({ schema })(req, res);
});
};
Monitoring and Logging
Add monitoring to detect introspection abuse attempts:
const { graphql } = require('@feathersjs/graphql');
const { schema } = require('./schema');
const logger = require('./logger');
module.exports = app => {
app.use('/graphql', (req, res, next) => {
if (req.body && req.body.query) {
if (req.body.query.includes('__schema') || req.body.query.includes('__type')) {
logger.warn('Introspection query detected', {
ip: req.ip,
userAgent: req.get('User-Agent'),
timestamp: new Date().toISOString()
});
}
}
return graphql({ schema })(req, res);
});
};
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 |