Graphql Introspection in Dynamodb
How Graphql Introspection Manifests in Dynamodb
GraphQL introspection in DynamoDB environments creates unique attack vectors that combine API-level information disclosure with database-level access patterns. When GraphQL resolvers interact with DynamoDB, the introspection system can expose not just schema information but also underlying data access patterns and potential DynamoDB table structures.
A common manifestation occurs when GraphQL resolvers use DynamoDB DocumentClient operations without proper access controls. Consider a resolver that queries a DynamoDB table:
const getProducts = async (root, args, context) => {
const params = {
TableName: 'Products',
FilterExpression: 'category = :category',
ExpressionAttributeValues: { ':category': args.category }
};
return dynamodb.scan(params).promise();
};Through GraphQL introspection, an attacker can discover this resolver exists and craft queries that may trigger expensive DynamoDB operations. The introspection response reveals field names, argument types, and potentially the DynamoDB table names if resolvers are poorly structured.
DynamoDB's provisioned throughput and on-demand capacity modes make introspection particularly dangerous. An attacker can use introspection to identify resolvers that perform scan operations (which read entire tables) versus query operations (which use indexes). They can then craft queries that maximize read capacity consumption:
query IntrospectionAttack {
__schema {
types {
name
fields {
name
args {
name
type { name }
}
}
}
}
}This query alone can consume significant DynamoDB read capacity as the GraphQL server processes the introspection request, potentially triggering DynamoDB's throttling mechanisms or incurring unexpected costs in on-demand mode.
Dynamodb-Specific Detection
Detecting GraphQL introspection vulnerabilities in DynamoDB contexts requires examining both the GraphQL layer and the underlying DynamoDB interactions. middleBrick's scanning approach identifies these issues through several DynamoDB-specific patterns.
First, middleBrick analyzes the GraphQL schema for resolvers that directly expose DynamoDB operations. The scanner looks for patterns like:
const resolvers = {
Query: {
getAllUsers: () => dynamodb.scan({ TableName: 'Users' }).promise(),
getUserById: (root, { id }) => dynamodb.get({ TableName: 'Users', Key: { id } }).promise()
}
};The scanner flags direct DynamoDB calls in resolvers as high-risk because they often lack the abstraction layer that would implement proper access controls. middleBrick also tests for introspection endpoint availability without authentication, which is a critical finding for any production API.
middleBrick's LLM/AI security module specifically tests for system prompt leakage that might reveal DynamoDB table structures or access patterns. The scanner uses 27 regex patterns to detect configuration data that could include DynamoDB endpoint URLs, region configurations, or table names embedded in error messages or logging.
For DynamoDB-specific rate limiting detection, middleBrick simulates GraphQL queries that would trigger DynamoDB operations at scale. The scanner measures response times and error patterns to identify whether the API properly handles high-volume introspection requests that could lead to DynamoDB throttling or cost escalation.
The scanner also checks for proper error handling in DynamoDB operations. Exposed error messages that reveal table names, partition keys, or sort key structures provide attackers with valuable information for crafting targeted attacks.
Dynamodb-Specific Remediation
Remediating GraphQL introspection vulnerabilities in DynamoDB environments requires a defense-in-depth approach that addresses both the GraphQL API layer and the DynamoDB data access patterns.
First, implement proper GraphQL introspection controls:
const introspectionRule = new graphql.Rule({
fieldName: '__schema',
resolve: async (root, args, context, info) => {
if (!context.user || !context.user.isAdmin) {
throw new Error('Introspection access denied');
}
return info.defaultFieldResolver(root, args, context, info);
}
});This middleware restricts introspection access to authenticated administrative users only, preventing unauthenticated attackers from discovering your GraphQL schema and underlying DynamoDB structures.
Next, implement DynamoDB-specific access controls using IAM policies that limit what operations resolvers can perform:
const dynamodbIAMPolicy = {
Version: '2012-10-17',
Statement: [
{
Effect: 'Allow',
Action: [
'dynamodb:GetItem',
'dynamodb:Query',
'dynamodb:PutItem',
'dynamodb:UpdateItem',
'dynamodb:DeleteItem'
],
Resource: 'arn:aws:dynamodb:us-east-1:123456789012:table/Products'
}
]
};This policy ensures resolvers can only access specific DynamoDB tables and operations, preventing accidental exposure of sensitive data through GraphQL queries.
For cost and performance protection, implement DynamoDB-specific rate limiting at the GraphQL layer:
const rateLimiter = new RateLimiterRedis({
storeClient: redisClient,
keyPrefix: 'graphql_dynamodb',
points: 100, // 100 requests
duration: 60 // per minute
});
const protectedResolver = async (resolve, parent, args, context, info) => {
await rateLimiter.consume(context.ip);
return resolve(parent, args, context, info);
};This prevents attackers from overwhelming your DynamoDB capacity with GraphQL introspection or query abuse.
Finally, implement proper error handling that doesn't leak DynamoDB-specific information:
const safeDynamoDBCall = async (params) => {
try {
return await dynamodb.send(new GetItemCommand(params)).promise();
} catch (error) {
console.error('Database operation failed');
throw new Error('Unable to process request at this time');
}
};This approach ensures that DynamoDB errors don't reveal table structures, partition keys, or other sensitive information through GraphQL error responses.
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 |