Skenario 07 / 26FAIL

Excessive Data Exposure - GraphQL - Schema Introspection

Lingkungan lab — bukan sistem produksi

Tangkapan layar dan trafik mentah tidak diterjemahkan; teks di dalamnya mungkin menggunakan bahasa lain.

vuln-bank/Evidence/[FAIL] Excessive Data Exposure - GraphQL - Schema Introspection

01 — Catatan

Catatan pengujian

Kerentanan

[FAIL] Excessive Data Exposure - GraphQL - Schema Introspection

Deskripsi

Endpoint /graphql melayani query introspeksi __schema bagi pengguna terautentikasi biasa. Seluruh tipe, field, dan argumen skema dapat diunduh, termasuk field yang tidak dipakai antarmuka resmi.

Dampak

Low: introspeksi memberi penyerang peta lengkap permukaan serangan GraphQL tanpa perlu menebak nama field. Informasi ini mempercepat penemuan kerentanan lain pada lapisan yang sama; pada pengujian ini, argumen accountNumber yang terungkap dari skema menjadi titik masuk temuan SQL Injection pada resolver transactionSummary. Introspeksi sendiri tidak membocorkan data nasabah.

CWE

CWE-200: Exposure of Sensitive Information to an Unauthorized Actor

OWASP

A05:2021 - Security Misconfiguration

Skenario

Eksploitasi: query __schema dikirim memakai token pengguna biasa -> seluruh definisi tipe dan field dikembalikan, termasuk resolver transactionSummary beserta argumennya.

Endpoint

POST http://127.0.0.1:5001/graphql

Fitur terdampak

Endpoint GraphQL

Rekomendasi perbaikan

- Matikan introspeksi pada lingkungan produksi. - Terapkan allow-list query (persisted queries) agar hanya operasi yang dikenal dapat dijalankan. - Batasi kedalaman dan kompleksitas query serta terapkan rate limiting. - Pastikan setiap resolver menjalankan pemeriksaan otorisasinya sendiri.

Bukti konsep

1) (Screenshot 1) EKSPLOITASI: query introspeksi __schema dikirim dengan token pengguna biasa -> seluruh tipe dan field skema dikembalikan, termasuk resolver transactionSummary beserta argumennya.
Lihat catatan sumber (bahasa Indonesia)
Vulnerability:
[FAIL] Excessive Data Exposure - GraphQL - Schema Introspection

Description:
Endpoint /graphql melayani query introspeksi __schema bagi pengguna terautentikasi biasa. Seluruh tipe, field, dan argumen skema dapat diunduh, termasuk field yang tidak dipakai antarmuka resmi.

Impact:
Low: introspeksi memberi penyerang peta lengkap permukaan serangan GraphQL tanpa perlu menebak nama field. Informasi ini mempercepat penemuan kerentanan lain pada lapisan yang sama; pada pengujian ini, argumen accountNumber yang terungkap dari skema menjadi titik masuk temuan SQL Injection pada resolver transactionSummary. Introspeksi sendiri tidak membocorkan data nasabah.

CWE:
CWE-200: Exposure of Sensitive Information to an Unauthorized Actor

OWASP:
A05:2021 - Security Misconfiguration

Scenario:
Eksploitasi: query __schema dikirim memakai token pengguna biasa -> seluruh definisi tipe dan field dikembalikan, termasuk resolver transactionSummary beserta argumennya.

Endpoint:
POST http://127.0.0.1:5001/graphql

Affected Feature:
Endpoint GraphQL

Remediation:
- Matikan introspeksi pada lingkungan produksi.
- Terapkan allow-list query (persisted queries) agar hanya operasi yang dikenal dapat dijalankan.
- Batasi kedalaman dan kompleksitas query serta terapkan rate limiting.
- Pastikan setiap resolver menjalankan pemeriksaan otorisasinya sendiri.

POC:
1) (Screenshot 1) EKSPLOITASI: query introspeksi __schema dikirim dengan token pengguna biasa -> seluruh tipe dan field skema dikembalikan, termasuk resolver transactionSummary beserta argumennya.

02 — Tangkapan layar

Tangkapan layar (1)

01 / 1

03 — Request dan response

Rekaman HTTP

Sebagian nilai kredensial disamarkan pada tampilan HTML publik ini. Penyamaran ini tidak menjamin bahwa seluruh data sensitif atau berkas tertaut sudah disamarkan.

REKAMAN 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 ...]