HIGH graphql introspectionadonisjsdynamodb

Graphql Introspection in Adonisjs with Dynamodb

Graphql Introspection in Adonisjs with Dynamodb — how this specific combination creates or exposes the vulnerability

GraphQL introspection is a feature that allows clients to query the schema for types, queries, and mutations. In AdonisJS, when GraphQL is implemented—commonly via packages such as adonisjs-graphql-client or similar integrations—and backed by DynamoDB as the persistence layer, introspection is often enabled in development or misconfigured in production. This exposes the full schema, including query names, arguments, and response shapes, without authentication.

DynamoDB itself does not enforce schema definitions at the GraphQL layer; the schema is defined in AdonisJS code and passed to the GraphQL server. If introspection is not explicitly disabled, an attacker can send an introspection query (standard GraphQL operation) to the endpoint and retrieve the entire API structure. This reveals sensitive data models, such as which DynamoDB tables are queried and the shape of returned items, including potential PII fields.

When combined, AdonisJS (as the framework exposing the GraphQL endpoint) and DynamoDB (as the data store) create a risk where introspection provides an attacker with knowledge of data access patterns. For example, an introspection query can reveal a user query that fetches items from a DynamoDB table where partition keys align with user identifiers. This supports further attacks like BOLA/IDOR, where guessed identifiers map to DynamoDB items. Introspection does not require authentication in AdonisJS unless explicitly guarded, and DynamoDB’s lack of native schema awareness means the framework must enforce access controls, which introspection bypasses by exposing those controls.

Real-world attack patterns include using introspection output to identify fields that may return API keys or tokens stored as attributes in DynamoDB items, or to discover query names that map to privileged operations. While DynamoDB handles data storage and access permissions, the GraphQL layer in AdonisJS defines what is queryable; introspection exposes that definition, increasing the risk of information leakage even when DynamoDB enforces its own policies.

Dynamodb-Specific Remediation in Adonisjs — concrete code fixes

To mitigate GraphQL introspection risks in AdonisJS when using DynamoDB, disable introspection in production and enforce strict schema and access controls. Below are specific, actionable fixes with working code examples.

1. Disable introspection in production

Configure your GraphQL server to disable introspection when not in development. Using a typical setup (e.g., apollo-server or graphql-http), set introspection to false outside development.

const { ApolloServer } = require('apollo-server-adonis')

const server = new ApolloServer({
  typeDefs,
  resolvers,
  introspection: process.env.NODE_ENV !== 'production',
})

2. Validate and scope DynamoDB queries in resolvers

Ensure resolvers reference only intended DynamoDB operations and enforce ownership at the data layer. Use the AWS SDK for JavaScript to interact with DynamoDB, and apply key condition expressions and filters rigorously.

const { DynamoDBClient, GetItemCommand } = require('@aws-sdk/client-dynamodb')
const { unmarshall } = require('@aws-sdk/util-dynamodb')

class UserResolver {
  constructor() {
    this.client = new DynamoDBClient({ region: 'us-east-1' })
  }

  async user(_, { id }, { auth }) {
    const userId = auth?.userId
    if (!userId || userId !== id) {
      throw new Error('Unauthorized')
    }

    const cmd = new GetItemCommand({
      TableName: process.env.USERS_TABLE,
      Key: {
        userId: { S: id },
      },
    })

    const resp = await this.client.send(cmd)
    return resp.Item ? unmarshall(resp.Item) : null
  }
}

3. Use environment-based schema composition

Compose your GraphQL schema conditionally to include or exclude types and queries based on environment, reducing exposure in production.

let typeDefs = gql`
  type User {
    id: ID!
    email: String!
  }

  type Query {
    user(id: ID!): User
  }
`

if (process.env.NODE_ENV !== 'production') {
  typeDefs = gql`
    ${typeDefs}
    type Query {
      _schema: String
    }
  `
}

4. Enforce authorization before DynamoDB access

Implement checks in resolvers to verify that the requesting user has permission to access or modify specific DynamoDB items. Never rely on client-supplied parameters alone for access decisions.

const { DynamoDBClient, QueryCommand } = require('@aws-sdk/client-dynamodb')
const { unmarshall } = require('@aws-sdk/util-dynamodb')

class PostResolver {
  constructor() {
    this.client = new DynamoDBClient({ region: 'us-east-1' })
  }

  async posts(_, __, { auth }) {
    if (!auth?.userId) {
      throw new Error('Unauthorized')
    }

    const cmd = new QueryCommand({
      TableName: process.env.POSTS_TABLE,
      KeyConditionExpression: 'userId = :uid',
      ExpressionAttributeValues: {
        ':uid': { S: auth.userId },
      },
    })

    const resp = await this.client.send(cmd)
    return resp.Items.map(unmarshall)
  }
}

These steps reduce the attack surface by limiting introspection, tightening DynamoDB query scoping, and ensuring authorization checks are performed in AdonisJS resolvers.

Related CWEs: dataExposure

CWE IDNameSeverity
CWE-200Exposure of Sensitive Information HIGH
CWE-209Error Information Disclosure MEDIUM
CWE-213Exposure of Sensitive Information Due to Incompatible Policies HIGH
CWE-215Insertion of Sensitive Information Into Debugging Code MEDIUM
CWE-312Cleartext Storage of Sensitive Information HIGH
CWE-359Exposure of Private Personal Information (PII) HIGH
CWE-522Insufficiently Protected Credentials CRITICAL
CWE-532Insertion of Sensitive Information into Log File MEDIUM
CWE-538Insertion of Sensitive Information into Externally-Accessible File HIGH
CWE-540Inclusion of Sensitive Information in Source Code HIGH

Frequently Asked Questions

Can GraphQL introspection be safely enabled in production if properly guarded?
It is not recommended. Introspection exposes schema details that can aid attackers. Disable it in production and rely on authenticated, scoped queries instead.
Does DynamoDB enforce any schema restrictions that mitigate introspection risks?
No. DynamoDB is schema-less at the query layer; the GraphQL schema in AdonisJS defines what is exposed. Introspection risks must be addressed at the GraphQL server level in the framework.