Test case 23 / 26PASS
Broken Object Level Authorization - GraphQL - Transaction Summary
Lab environment — not a production system
Screenshots and raw traffic are not translated; text within them may be in another language.
vuln-bank/Evidence/[PASS] Broken Object Level Authorization - GraphQL - Transaction Summary
01 — Notes
Test notes
Vulnerability
[PASS] Broken Object Level Authorization - GraphQL - Transaction Summary
Description
The test attempted to read another user's transaction summary through the accountNumber argument of the GraphQL transactionSummary resolver, including the victim's account and the administrator's account.
Impact
No impact. Control holds: the resolver compares the requested accountNumber with the account owned by the token holder and rejects cross-object requests with an explicit error. Ordinary users can only read the transaction summary of their own account.
Note: the same code path is still flawed for callers with the administrator role, because the argument value is passed into the SQL query without parameterization; this is reported separately in the SQL Injection - GraphQL finding.
CWE
CWE-639: Authorization Bypass Through User-Controlled Key
OWASP
A01:2021 - Broken Access Control
Scenario
Normal: an ordinary user requests their own account transaction summary -> succeeds. Attempt: accountNumber is changed to the victim's account -> rejected. Attempt: accountNumber is changed to the administrator's account -> rejected.
Endpoint
POST http://127.0.0.1:5001/graphql
Affected feature
GraphQL transactionSummary (object authorization)
Remediation
- Keep the account ownership check in the resolver.
- Add parameterized queries so the same argument does not become an injection point for higher-privileged callers.
Proof of concept
1) (Screenshot 1) NORMAL: an ordinary user requests their own account transaction summary -> succeeds.
2) (Screenshot 2) ATTEMPT: accountNumber is changed to the victim's account -> rejected with the error You can only query your own transaction summary, control holds.
3) (Screenshot 3) ATTEMPT: accountNumber is changed to the administrator's account -> rejected, control holds.
View source note (English)
Vulnerability:
[PASS] Broken Object Level Authorization - GraphQL - Transaction Summary
Description:
The test attempted to read another user's transaction summary through the accountNumber argument of the GraphQL transactionSummary resolver, including the victim's account and the administrator's account.
Impact:
No impact. Control holds: the resolver compares the requested accountNumber with the account owned by the token holder and rejects cross-object requests with an explicit error. Ordinary users can only read the transaction summary of their own account.
Note: the same code path is still flawed for callers with the administrator role, because the argument value is passed into the SQL query without parameterization; this is reported separately in the SQL Injection - GraphQL finding.
CWE:
CWE-639: Authorization Bypass Through User-Controlled Key
OWASP:
A01:2021 - Broken Access Control
Scenario:
Normal: an ordinary user requests their own account transaction summary -> succeeds. Attempt: accountNumber is changed to the victim's account -> rejected. Attempt: accountNumber is changed to the administrator's account -> rejected.
Endpoint:
POST http://127.0.0.1:5001/graphql
Affected Feature:
GraphQL transactionSummary (object authorization)
Remediation:
- Keep the account ownership check in the resolver.
- Add parameterized queries so the same argument does not become an injection point for higher-privileged callers.
POC:
1) (Screenshot 1) NORMAL: an ordinary user requests their own account transaction summary -> succeeds.
2) (Screenshot 2) ATTEMPT: accountNumber is changed to the victim's account -> rejected with the error You can only query your own transaction summary, control holds.
3) (Screenshot 3) ATTEMPT: accountNumber is changed to the administrator's account -> rejected, control holds.
02 — Screenshots
Screenshots (3)
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: 148
{"query": "query($a:String){transactionSummary(accountNumber:$a,limit:3){scope accountNumber totalTransactions}}", "variables": {"a": "0932191785"}}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
}
}
}CAPTURE 02 / 2
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/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"
]
}
]
}CAPTURE 03 / 3
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/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"
]
}
]
}