Graphql Introspection in Adonisjs
How Graphql Introspection Manifests in Adonisjs
GraphQL introspection is enabled by default in Adonisjs when using the @adonisjs/graphql package. This feature allows clients to query the GraphQL schema to discover available types, queries, mutations, and fields. While useful for development and API documentation, it creates significant security risks in production environments.
In Adonisjs, introspection manifests through the GraphQL Playground and Voyager interfaces that are automatically served when the graphql route is accessed. These tools expose the entire schema structure, including:
- All available queries and mutations
- Input types and their fields
- Enum values and possible options
- Field arguments and their types
- Custom scalar definitions
- Interface and union type hierarchies
The risk is particularly acute in Adonisjs applications because the framework's convention-over-configuration approach means developers might not realize introspection is enabled. Consider this typical Adonisjs GraphQL setup:
const { Ignitor } = require('@adonisjs/core/Ignitor')
const { graphql } = require('@adonisjs/graphql')
const app = new Ignitor(__dirname)
.handle(({ app, ace }) => {
app
.router()
.get('/graphql', graphql.routes())
.post('/graphql', graphql.routes())
})
.catch(console.error)With this configuration, visiting /graphql exposes both the GraphQL endpoint and the interactive Playground interface. An attacker can immediately discover:
query {
__schema {
types {
name
kind
description
}
queries: queryType {
name
fields {
name
description
args {
name
type {
name
kind
}
}
}
}
}
}This reveals the complete API surface, enabling attackers to craft targeted exploits without trial-and-error. For Adonisjs applications using Lucid models, introspection also exposes database relationships and field structures, potentially revealing sensitive data patterns.
Adonisjs-Specific Detection
Detecting GraphQL introspection vulnerabilities in Adonisjs requires examining both the configuration and runtime behavior. Start by checking your Adonisjs configuration files for GraphQL settings.
In your config/graphql.js file, look for introspection settings:
module.exports = {
introspection: true, // This is the default and should be false in production
playground: process.env.NODE_ENV !== 'production', // Should be disabled in production
path: '/graphql',
// ... other settings
}middleBrick scans Adonisjs applications for this specific vulnerability by sending introspection queries to the GraphQL endpoint and analyzing the response. The scanner tests for:
- Direct access to
/graphqlwithout authentication - Successful introspection queries returning schema information
- Exposure of sensitive field names and types
- Presence of the GraphQL Playground interface in production
You can also perform manual detection using curl:
curl -X POST http://your-adonis-app.com/graphql \
-H "Content-Type: application/json" \
-d '{"query":"query { __schema { types { name } } }"}'If this returns type information, introspection is enabled. middleBrick's automated scanning goes further by testing 12 different security vectors simultaneously, including GraphQL-specific attacks like batching and recursive queries that could lead to denial-of-service conditions.
For Adonisjs applications using middleware, ensure your authentication middleware is properly applied to the GraphQL route:
const Route = use('Route')
const { graphql } = require('@adonisjs/graphql')
Route
.get('/graphql', 'AuthMiddleware', graphql.routes())
.post('/graphql', 'AuthMiddleware', graphql.routes())Without proper middleware protection, even if introspection is disabled, the GraphQL endpoint itself may be exposed to unauthenticated users.
Adonisjs-Specific Remediation
Remediating GraphQL introspection vulnerabilities in Adonisjs involves multiple layers of protection. The most straightforward fix is configuring the GraphQL package to disable introspection in production:
module.exports = {
introspection: process.env.NODE_ENV === 'development',
playground: process.env.NODE_ENV === 'development',
path: '/graphql',
// ... other settings
}This ensures introspection is only available during development. For additional security, implement authentication middleware on your GraphQL routes:
const Route = use('Route')
const { graphql } = require('@adonisjs/graphql')
Route
.get('/graphql', 'AuthMiddleware', graphql.routes())
.post('/graphql', 'AuthMiddleware', graphql.routes())Create an authentication middleware that checks for valid API keys or JWT tokens:
const Env = use('Env')
class AuthMiddleware {
async handle({ request, response }, next) {
const authHeader = request.header('Authorization')
if (!authHeader || !authHeader.startsWith('Bearer ')) {
return response.status(401).json({ error: 'Unauthorized' })
}
const token = authHeader.substring(7)
const valid = await this.verifyToken(token)
if (!valid) {
return response.status(401).json({ error: 'Unauthorized' })
}
await next()
}
async verifyToken(token) {
// Implement your token verification logic
return token === Env.get('API_KEY', '')
}
}
module.exports = AuthMiddlewareFor applications requiring schema documentation without exposing introspection, consider using GraphQL's @deprecated directive and custom schema documentation endpoints that don't reveal implementation details.
middleBrick can help verify your remediation by scanning the GraphQL endpoint after changes. The scanner will attempt introspection queries and report whether the vulnerability persists. This is particularly valuable for CI/CD pipelines where you can fail builds if security scores drop.
Additional hardening includes implementing rate limiting on GraphQL endpoints to prevent abuse, using query complexity analysis to prevent expensive queries, and logging all GraphQL requests for audit purposes. Adonisjs's built-in validation and sanitization features should be leveraged to ensure input data is properly validated before reaching your resolvers.
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 |