Kerentanan
[PASS] Broken Object Level Authorization - GraphQL - Transaction Summary
Deskripsi
Pengujian berupaya membaca ringkasan transaksi milik pengguna lain melalui argumen accountNumber pada resolver GraphQL transactionSummary, termasuk rekening korban dan rekening administrator.
Dampak
Tidak ada dampak. Kontrol bertahan: resolver membandingkan accountNumber yang diminta dengan rekening milik pemegang token dan menolak permintaan lintas objek dengan galat eksplisit. Pengguna biasa hanya dapat membaca ringkasan transaksi rekeningnya sendiri.
Catatan: jalur kode yang sama tetap bermasalah bagi pemanggil dengan peran administrator, karena nilai argumen diteruskan ke query SQL tanpa parameterisasi; hal tersebut dilaporkan terpisah pada temuan SQL Injection - GraphQL.
CWE
CWE-639: Authorization Bypass Through User-Controlled Key
OWASP
A01:2021 - Broken Access Control
Skenario
Normal: pengguna biasa meminta ringkasan transaksi rekeningnya sendiri -> berhasil. Percobaan: accountNumber diganti dengan rekening korban -> ditolak. Percobaan: accountNumber diganti dengan rekening administrator -> ditolak.
Endpoint
POST http://127.0.0.1:5001/graphql
Fitur terdampak
GraphQL transactionSummary (otorisasi objek)
Rekomendasi perbaikan
- Pertahankan pemeriksaan kepemilikan rekening pada resolver.
- Lengkapi dengan parameterized query agar argumen yang sama tidak menjadi titik injeksi bagi pemanggil dengan hak lebih tinggi.
Bukti konsep
- (Screenshot 1) NORMAL: pengguna biasa meminta ringkasan transaksi rekeningnya sendiri -> berhasil.
- (Screenshot 2) PERCOBAAN: accountNumber diganti dengan rekening korban -> ditolak dengan galat You can only query your own transaction summary, kontrol bertahan.
- (Screenshot 3) PERCOBAAN: accountNumber diganti dengan rekening administrator -> ditolak, kontrol bertahan.
Rekaman lengkap
LAB Semua target adalah sistem lab. Tidak ada satu pun yang merupakan pekerjaan klien. Bukti ditampilkan apa adanya; secret dihitamkan.
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: 148
{"query": "query($a:String){transactionSummary(accountNumber:$a,limit:3){scope accountNumber totalTransactions}}", "variables": {"a": "0932191785"}}
HTTP response
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 149
Access-Control-Allow-Origin: *
Server: Werkzeug/2.0.1 Python/3.9.25
Date: Wed, 30 Sep 2026 03:13:13 GMT
{
"data": {
"transactionSummary": {
"accountNumber": "0932191785",
"scope": "account",
"totalTransactions": 11
}
}
}
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: 148
{"query": "query($a:String){transactionSummary(accountNumber:$a,limit:3){scope accountNumber totalTransactions}}", "variables": {"a": "9159912486"}}
HTTP response
HTTP/1.1 400 BAD REQUEST
Content-Type: application/json
Content-Length: 361
Access-Control-Allow-Origin: *
Server: Werkzeug/2.0.1 Python/3.9.25
Date: Wed, 30 Sep 2026 03:13:14 GMT
{
"data": {
"transactionSummary": null
},
"errors": [
{
"message": "You can only query your own transaction summary.\n\nGraphQL request:1:18\n1 | query($a:String){transactionSummary(accountNumber:$a,limit:3){scope accountNumber totalTransactions}}\n | ^",
"path": [
"transactionSummary"
]
}
]
}
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: 146
{"query": "query($a:String){transactionSummary(accountNumber:$a,limit:3){scope accountNumber totalTransactions}}", "variables": {"a": "ADMIN001"}}
HTTP response
HTTP/1.1 400 BAD REQUEST
Content-Type: application/json
Content-Length: 361
Access-Control-Allow-Origin: *
Server: Werkzeug/2.0.1 Python/3.9.25
Date: Wed, 30 Sep 2026 03:13:15 GMT
{
"data": {
"transactionSummary": null
},
"errors": [
{
"message": "You can only query your own transaction summary.\n\nGraphQL request:1:18\n1 | query($a:String){transactionSummary(accountNumber:$a,limit:3){scope accountNumber totalTransactions}}\n | ^",
"path": [
"transactionSummary"
]
}
]
}
← Kasus sebelumnya: Broken Object Level Authorization - Accounts - Balance Lookup Kasus berikutnya: Broken Object Level Authorization - Merchant Payments - Payment By ID →