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)

01 / 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
HTTP request
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 response
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 ...]