Test case 24 / 26PASS
Broken Object Level Authorization - Merchant Payments - Payment By ID
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 - Merchant Payments - Payment By ID
01 — Notes
Test notes
Vulnerability
[PASS] Broken Object Level Authorization - Merchant Payments - Payment By ID
Description
The test attempted to read the details of another merchant's transaction through /api/v1/payments/<payment_id> using a different merchant's API key.
Impact
No impact. Control holds: the endpoint limits the lookup to transactions owned by the merchant holding the API key, so cross-merchant requests receive Payment not found instead of disclosing data.
Note: another endpoint in the same module does NOT apply this restriction. /api/v1/payments/merchant_id/<merchant_id> returns other merchants' transactions and is reported separately as the Broken Object Level Authorization - Merchant Payments - Payments By Merchant finding.
CWE
CWE-639: Authorization Bypass Through User-Controlled Key
OWASP
A01:2021 - Broken Access Control
Scenario
Normal: ScopeShopA reads its own transaction by payment_id using its own API key -> succeeds. Attempt: ScopeShopB reads the same payment_id using its own API key -> rejected with Payment not found.
Endpoint
GET http://127.0.0.1:5001/api/v1/payments/<payment_id>
Affected feature
Merchant payments (transaction detail by id)
Remediation
- Keep the restriction that limits transaction lookups to the merchant owning the API key.
- Apply the same pattern across all payment module endpoints, especially /api/v1/payments/merchant_id/<merchant_id> which currently does not restrict access.
Proof of concept
1) (Screenshot 1) NORMAL: ScopeShopA reads its own transaction using its own API key -> succeeds.
2) (Screenshot 2) ATTEMPT: ScopeShopB reads the same payment_id using its own API key -> rejected with Payment not found, control holds.
View source note (English)
Vulnerability:
[PASS] Broken Object Level Authorization - Merchant Payments - Payment By ID
Description:
The test attempted to read the details of another merchant's transaction through /api/v1/payments/<payment_id> using a different merchant's API key.
Impact:
No impact. Control holds: the endpoint limits the lookup to transactions owned by the merchant holding the API key, so cross-merchant requests receive Payment not found instead of disclosing data.
Note: another endpoint in the same module does NOT apply this restriction. /api/v1/payments/merchant_id/<merchant_id> returns other merchants' transactions and is reported separately as the Broken Object Level Authorization - Merchant Payments - Payments By Merchant finding.
CWE:
CWE-639: Authorization Bypass Through User-Controlled Key
OWASP:
A01:2021 - Broken Access Control
Scenario:
Normal: ScopeShopA reads its own transaction by payment_id using its own API key -> succeeds. Attempt: ScopeShopB reads the same payment_id using its own API key -> rejected with Payment not found.
Endpoint:
GET http://127.0.0.1:5001/api/v1/payments/<payment_id>
Affected Feature:
Merchant payments (transaction detail by id)
Remediation:
- Keep the restriction that limits transaction lookups to the merchant owning the API key.
- Apply the same pattern across all payment module endpoints, especially /api/v1/payments/merchant_id/<merchant_id> which currently does not restrict access.
POC:
1) (Screenshot 1) NORMAL: ScopeShopA reads its own transaction using its own API key -> succeeds.
2) (Screenshot 2) ATTEMPT: ScopeShopB reads the same payment_id using its own API key -> rejected with Payment not found, control holds.
02 — Screenshots
Screenshots (2)
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
GET /api/v1/payments/2 HTTP/1.1
User-Agent: python-requests/2.33.1
Accept-Encoding: gzip, deflate, br, zstd
Accept: */*
Connection: keep-alive
X-Merchant-Api-Key: vk_e14704c2e08923caa90cd6b2b939d13bd413b8338852903e96d41e7ad1e55ee2
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 796
Access-Control-Allow-Origin: *
Server: Werkzeug/2.0.1 Python/3.9.25
Date: Wed, 30 Sep 2026 03:13:16 GMT
{
"debug_info": {
"looked_up_by_merchant": {
"api_key": "[REDACTED-LAB-VALUE]",
"auth_method": "api_key",
"created_at": "2026-09-30 03:13:16.469526",
"email": "[REDACTED-EMAIL]",
"id": 5,
"is_active": true,
"name": "None"
}
},
"payment": {
"amount": 42.0,
"authorization_code": null,
"card_id": null,
"card_number": null,
"created_at": "2026-09-30 03:13:16.487849",
"currency": "USD",
"cvv": null,
"failure_reason": "invalid_card_number",
"id": 2,
"merchant_email": "[REDACTED-EMAIL]",
"merchant_id": 5,
"merchant_name": "None",
"merchant_order_id": null,
"payment_status": "failed"
},
"status": "success"
}CAPTURE 02 / 2
GET /api/v1/payments/2 HTTP/1.1
User-Agent: python-requests/2.33.1
Accept-Encoding: gzip, deflate, br, zstd
Accept: */*
Connection: keep-alive
X-Merchant-Api-Key: vk_cab3c9da252d39d384da572a2f04ad33c30cc92f166c33adaaac2533ebd385c9
HTTP/1.1 404 NOT FOUND
Content-Type: application/json
Content-Length: 79
Access-Control-Allow-Origin: *
Server: Werkzeug/2.0.1 Python/3.9.25
Date: Wed, 30 Sep 2026 03:13:17 GMT
{
"message": "Payment not found",
"payment_id": 2,
"status": "error"
}