How-To
Test a GraphQL API

How to Test a GraphQL API

Install NAT

pip install nat-engine

Identify your GraphQL endpoint

Most GraphQL APIs use a single endpoint. Common paths:

  • /graphql
  • /api/graphql
  • /v1/graphql

Confirm by sending a simple introspection query:

curl -X POST https://api.example.com/graphql \
  -H 'Content-Type: application/json' \
  -d '{"query":"{ __typename }"}'

If you get a JSON response with "data": {"__typename": "Query"}, the endpoint is live.

Run a basic GraphQL scan

nat scan \
  --url https://api.example.com \
  --graphql \
  --graphql-endpoint /graphql

If your GraphQL API is at the root URL:

nat scan --url https://api.example.com/graphql --graphql

Add authentication

nat scan \
  --url https://api.example.com \
  --graphql \
  --auth-type bearer \
  --token "$YOUR_JWT"

Provide a schema if introspection is disabled

If your API disables introspection (as it should in production), provide the schema file:

nat scan \
  --url https://api.example.com \
  --graphql \
  --graphql-schema ./schema.graphql \
  --auth-type bearer \
  --token "$TOKEN"

Export your schema from a development environment where introspection is enabled, then use it for production scans where introspection is disabled.

Add example queries for better coverage

Seed NAT with representative queries and mutations:

nat scan \
  --url https://api.example.com \
  --graphql \
  --graphql-queries ./queries.graphql \
  --auth-type bearer \
  --token "$TOKEN"

Add a second user token for BOLA testing

nat scan \
  --url https://api.example.com \
  --graphql \
  --auth-type bearer \
  --token "$USER_A_TOKEN" \
  --secondary-token "$USER_B_TOKEN"

This enables NAT to test whether User A can access User B's data through GraphQL queries.

Review findings

nat report --open

Key things to look for in GraphQL scan results:

  • BOLA findings — can users query each other's data?
  • Introspection enabled — should be disabled in production
  • Query depth/complexity — missing limits lead to DoS risk
  • Field-level auth — are sensitive fields protected per-role?

GraphQL-specific findings to watch for

FindingWhy it matters
Introspection enabled in productionExposes full schema to attackers
No query depth limitDeeply nested queries can crash your server
No query complexity limitComplex queries create N+1 database load
BOLA via queryUser A can fetch User B's private data
Mass assignment via mutationMutation accepts fields that shouldn't be writable

Next steps