the deliverable, per finding
idor-order-history-report.zip
├── report.md
├── evidence/
│ ├── poc.sh
│ ├── request-order-1002.http
│ ├── response-order-1002.json
│ └── enumeration-log.txt
└── CHECKSUMS.txt
report.md
IDOR: sequential order IDs expose other customers' full order history
- Asset
- https://api.acme.example/v1/orders
- Severity
- Critical
- CWE
- CWE-639
- CVSS
- CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H (9.1)
- VRT
- Access Control (BAC)
- ISO 27001
- A.8.26 · A.8.9 (2022)
- NIS2
- § 30 Abs. 2 Nr. 5 + Nr. 6 BSIG
Impact
Authenticated order IDs are sequential and the API never checks ownership. Any logged-in customer can read the full order history of any other customer, items, addresses and payment references, by incrementing the ID. No privilege escalation: one low-value test account exposes every other account.
Description
GET /v1/orders/{id} and /v1/orders/{id}/items return full records for any id. The ownership check exists only in the frontend; the API accepts the session of any authenticated user for any order id.
Reproduction
- 1Log in as the provided test account (testuser1) and keep the session cookie.
- 2GET /v1/orders/1001: own order, HTTP 200 (baseline).
- 3GET /v1/orders/1002: another customer's order, HTTP 200, full payload (evidence/response-order-1002.json).
- 4Run evidence/poc.sh: enumerates ids 1001 to 1010, all return 200 (evidence/enumeration-log.txt).
Evidence
- evidence/poc.sh: working PoC (bash, read-only)
- evidence/request-order-1002.http: raw request
- evidence/response-order-1002.json: full order payload of a foreign account
- evidence/enumeration-log.txt: 41 foreign orders read
Remediation
Enforce object-level authorization: resolve the owner server-side from the authenticated session and reject requests where the resource owner does not match; add regression test coverage.
evidence/poc.sh
#!/usr/bin/env bash
# PoC: IDOR on /v1/orders/{id} (acme.example, fictitious sample)
# Read-only: uses the customer-provided test account, mutates nothing.
BASE="https://api.acme.example/v1"
COOKIE="session=***" # testuser1
for id in $(seq 1001 1010); do
code=$(curl -s -o /dev/null -w '%{http_code}' -H "Cookie: $COOKIE" "$BASE/orders/$id")
echo "order $id -> HTTP $code"
done
# observed: 1001 = 200 (own), 1002..1010 = 200 (other customers' orders)CHECKSUMS.txt
3f2ac91e… evidence/poc.sh
b81e44d0… evidence/request-order-1002.http
d4c07a19… evidence/response-order-1002.json
9e5f22b6… evidence/enumeration-log.txt
The loop, on this finding
- First found
- 24.08.2026
- Fixed
- 25.08.2026 (release 2026.08.2)
- Retested
- 26.08.2026, verified closed
One high (SQL injection in /api/login) stays open in the next cycle, because that is the honest state. It closes after fix and retest, by 15.09.2026 at the latest.
Attestation
Rheono, named researcher Samir Abis, tested the scope above externally and non-destructively. Every finding was verified manually by proof of concept. No guarantee of the completeness of all weaknesses and no guarantee of regulatory compliance.
Next snapshot: by 08.12.2026 or right after the next release.
Signature
Samir Abis · named researcher, rheono
Advanced electronic signature (eIDAS, PAdES-B-T) + qualified timestamp (RFC 3161)
More about the processPentest cost: what the market chargesTrust & security