Vulnerabilities
GraphQL Introspection vs Production APIs
January 29, 2024
GraphQL introspection vs production APIs is a schema-publication choice, not an automatic CVE. Introspection lets clients query __schema and learn types, fields, and arguments. That is appropriate for public developer platforms and a miss for private product APIs that never meant to publish the catalog. Turning introspection off does not replace authentication, authorization, or query cost limits. RoastMyOpsec's app-mode check sends one bounded, unauthenticated, read-only introspection POST to /graphql. It does not dump your data or brute-force resolvers.
The practical difference
A REST OpenAPI file you chose to publish is similar: documentation is not RCE. The OPSEC question is whether strangers should get a complete field list for an authenticated product graph.
Introspection on is convenient for GraphiQL in staging. Production private APIs usually disable it and keep schema docs in an authenticated developer portal.
How to choose based on the API's job
If the GraphQL endpoint is a public platform with documented types, introspection can stay on behind rate limits. If it backs a logged-in SaaS, disable introspection in production and require auth on every operation. Nested queries still need depth and complexity limits either way.
| API type | Introspection in prod | Still required | Takeaway |
|---|---|---|---|
| Public developer graph | Often on | Auth where data is private; rate limits | The schema is a product |
| Private SaaS /graphql | Usually off | Authz on every field class | Do not publish the menu |
| Staging only | On behind VPN or basic auth | Do not copy the flag to prod | Same binary, different config |
| Federated graphs | Per subgraph policy | Gateway still needs cost limits | One open subgraph can narrate the rest |
When disabling introspection is not enough
Field suggestions, error messages, and unauthenticated mutations are separate issues. A locked schema with open resolvers is still a data problem.
Pair production config with boring errors, persisted queries if you use them, and WAF/rate limits on /graphql.
Common mistakes
The first mistake is leaving the default 'introspection on' from a tutorial.
The second mistake is disabling introspection and calling the API 'private' with no auth on queries.
The third mistake is exposing GraphiQL on the production host.
Free audit the URL you own
RoastMyOpsec is a defensive public-surface roast: headers, cookies, sensitive paths, and more — no exploit payloads. Start with the free audit, then open the vault if the blurred findings look expensive.
Free audit nowFAQ
- Is GraphQL introspection a vulnerability?
- Usually no. It is information disclosure. It becomes urgent when the graph is private and the schema reveals admin-only types you did not intend to advertise.
- Does turning introspection off hide all types?
- No. Clients can still learn from errors, suggested fields, and any types they are allowed to query. Authorization still has to be real.
- How does RoastMyOpsec test GraphQL?
- One bounded unauthenticated POST with a read-only __schema query to /graphql. No mutation payloads, no nested attack queries.
Sources
Related guides
Vulnerabilities
Swagger UI vs GraphQL Introspection on Production APIsVulnerabilities
CORS Wildcard vs Allowlist for Public APIsVulnerabilities
Public JavaScript API Keys vs Server Secrets