Graphql Introspection on Docker
How Graphql Introspection Manifests in Docker
GraphQL introspection is a powerful feature that allows clients to query the schema of a GraphQL API, but when exposed in Dockerized environments, it creates significant security risks. In Docker deployments, GraphQL servers often run as containers with predictable configurations, making them easier targets for attackers who can discover exposed introspection endpoints.
The most common manifestation occurs when GraphQL servers are deployed without proper security middleware. For example, a Node.js GraphQL server running in a Docker container might expose the standard /graphql endpoint with introspection enabled by default. Attackers can send IntrospectionQuery requests to enumerate all types, fields, mutations, and subscriptions available in the API.
In Docker environments, this becomes more dangerous because:
- Containers often use predictable naming conventions and network configurations
- Development environments frequently mirror production setups
- GraphQL servers might be exposed on multiple ports (8080, 4000, 5000) across different containers
- Service discovery tools can automatically locate GraphQL endpoints
A typical vulnerable setup in Docker might look like this in a docker-compose.yml:
version: '3.8'
services:
graphql-api:
build: .
ports:
- "4000:4000"
environment:
- NODE_ENV=development
volumes:
- ./src:/app/srcThis configuration exposes the GraphQL endpoint on port 4000 without any authentication or rate limiting. An attacker could then send a simple introspection query:
{
__schema {
types {
name
fields {
name
}
}
}
}The response reveals the complete API structure, including sensitive field names, argument types, and available mutations. In Docker environments, this information can be combined with container metadata to identify potential attack vectors across the entire microservices architecture.
Another Docker-specific manifestation occurs when GraphQL servers are proxied through Nginx or similar reverse proxies. If the proxy configuration doesn't properly handle GraphQL introspection headers, attackers can bypass security controls by targeting the internal GraphQL container directly through the Docker network.
Docker-Specific Detection
Detecting GraphQL introspection vulnerabilities in Docker environments requires both network-level and application-level scanning. The most effective approach combines automated scanning with manual verification of container configurations.
Network-level detection involves scanning exposed ports across all Docker containers. Tools like docker ps and docker network ls can identify running containers and their network configurations. For GraphQL endpoints specifically, you can use curl to test for introspection support:
# Scan all running containers for GraphQL endpoints
for container_id in $(docker ps -q); do
container_name=$(docker inspect --format='{{.Name}}' $container_id)
container_ports=$(docker inspect --format='{{range .NetworkSettings.Ports}}{{.}} {{end}}' $container_id)
# Test common GraphQL ports
for port in 4000 8080 5000; do
if echo $container_ports | grep -q ":$port"; then
echo "Testing $container_name on port $port"
curl -s -X POST http://localhost:$port/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{__schema{types{name}}}"}' | grep -q "__schema" && \
echo " ✓ Introspection enabled"
fi
done
doneThis script identifies containers with exposed GraphQL endpoints and tests whether introspection is enabled. However, manual testing alone is insufficient for production environments.
middleBrick provides automated GraphQL introspection scanning specifically designed for Docker environments. The tool performs black-box scanning of API endpoints without requiring credentials or configuration. When scanning Docker-deployed APIs, middleBrick:
- Detects exposed GraphQL endpoints across all network interfaces
- Tests for introspection support using standardized queries
- Analyzes the returned schema for sensitive information exposure
- Checks for default configurations that might indicate development environments
The scanning process takes 5-15 seconds and provides a security risk score (A-F) with prioritized findings. For GraphQL introspection specifically, middleBrick checks whether the endpoint allows unauthenticated access to schema information, which is a critical security finding.
Additional detection methods include:
# Check Docker logs for GraphQL errors that might reveal schema information
docker logs $(docker ps -q) 2>&1 | grep -i "graphql\|schema" | head -10
# Scan for common GraphQL error messages that expose internal structure
docker exec $(docker ps -q) \
curl -s -X POST http://localhost:4000/graphql \
-H "Content-Type: application/json" \
-d '{"query":"{__type(name: \"User\"){name}}", "variables":null}' | \
grep -E "(Cannot query field|Unknown type)"These commands help identify containers that might be leaking schema information through error messages or debug output.
Docker-Specific Remediation
Remediating GraphQL introspection vulnerabilities in Docker environments requires a multi-layered approach that combines configuration changes, code modifications, and deployment best practices. The goal is to disable introspection in production while maintaining it for development and testing environments.
The most straightforward remediation is to disable introspection at the GraphQL server level. For Apollo Server in Node.js, this can be done in the server configuration:
const { ApolloServer, gql } = require('apollo-server');
const typeDefs = gql`
type Query {
hello: String
}
`;
const resolvers = {
Query: {
hello: () => 'Hello world!'
}
};
const server = new ApolloServer({
typeDefs,
resolvers,
introspection: process.env.NODE_ENV === 'development',
playground: process.env.NODE_ENV === 'development'
});
server.listen({ port: 4000 }).then(({ url }) => {
console.log(`Server ready at ${url}`);
});This configuration uses the NODE_ENV environment variable to control whether introspection and the GraphQL playground are enabled. In Docker, this translates to:
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 4000
ENV NODE_ENV=production
CMD ["node", "server.js"]For Docker Compose, you can override the environment variable for development:
version: '3.8'
services:
graphql-api:
build: .
ports:
- "4000:4000"
environment:
- NODE_ENV=production
deploy:
resources:
limits:
memory: 512MAnother effective approach is implementing middleware that blocks introspection queries. This can be done with custom Apollo Server plugins:
const { ApolloServer, gql } = require('apollo-server');
const url = require('url');
const server = new ApolloServer({
typeDefs,
resolvers,
plugins: [
{
requestDidStart: () => ({
didResolveOperation: async (requestContext) => {
const { query } = requestContext.request;
if (query.includes('__schema') || query.includes('__type')) {
throw new Error('Introspection queries are not allowed in production');
}
}
})
}
]
});For Docker deployments, you can also implement network-level controls using Nginx as a reverse proxy:
upstream graphql_api {
server graphql:4000;
}
server {
listen 80;
server_name graphql.example.com;
location /graphql {
if ($arg_query ~* "__schema|__type") {
return 403;
}
proxy_pass http://graphql_api;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}This configuration blocks introspection queries at the proxy level before they reach the GraphQL server. In Docker Compose, you would add an Nginx service that proxies to the GraphQL container.
Additional remediation steps include:
# Update Docker Compose to use a network with proper isolation
version: '3.8'
services:
graphql-api:
build: .
networks:
- api-network
environment:
- NODE_ENV=production
nginx:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
networks:
- api-network
depends_on:
- graphql-api
networks:
api-network:
driver: bridgeThis setup isolates the GraphQL API on a dedicated network and only exposes it through the Nginx reverse proxy, which implements the introspection blocking rules.
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 |
Frequently Asked Questions
How can I test if my Dockerized GraphQL API has introspection enabled?
curl -X POST -H "Content-Type: application/json" -d '{"query":"{__schema{types{name}}}"}' http://localhost:4000/graphql. If you receive a response containing schema information, introspection is enabled. For automated testing in Docker environments, middleBrick can scan your API endpoints in 5-15 seconds and provide a security risk score with specific findings about introspection vulnerabilities.