Cheesy Does It: IDOR + Price Manipulation
Overview
- Platform: BugForge
- Vulnerability: IDOR (Insecure Direct Object Reference), Client-Side Price Manipulation, Wildcard CORS
- Key Technique: Sequential ID enumeration on order detail endpoint to access other users’ orders
- Result: Exfiltrated PII (delivery address, phone number, full order details) from another user’s order, captured flag
Objective
Find and exploit vulnerabilities in a pizza ordering web application.
Initial Access
# Target Application
URL: https://lab-1774282941051-p9wejy.labs-app.bugforge.io
# Auth details
Registered user: haxor (id=4)
Second user: victim1 (id=7)
Auth mechanism: JWT HS256 (payload: {id, username, iat})
Key Findings
-
IDOR on Order Detail Endpoint (CWE-639: Authorization Bypass Through User-Controlled Key) — Any authenticated user can read any order by ID. No ownership check on
GET /api/orders/:id. Exposes delivery address, phone number, and full order details. -
Client-Side Price Manipulation (CWE-602: Client-Side Enforcement of Server-Side Security) — Server trusts client-supplied
unit_priceandtotal_priceinPOST /api/orders. Also trusts client-suppliedamountinPOST /api/payment/process. Accepted $0 and negative amounts. -
Wildcard CORS (CWE-942: Permissive Cross-domain Policy) — All API endpoints return
Access-Control-Allow-Origin: *. Enables cross-origin exploitation of the IDOR and price manipulation vulnerabilities.
Attack Chain Visualization
┌──────────────┐ ┌───────────────┐ ┌──────────────────┐
│ Register │ │ Register │ │ Create order │
│ as haxor │────>│ as victim1 │────>│ as victim1 │
│ (id=4) │ │ (id=7) │ │ (order id=4) │
└──────────────┘ └───────────────┘ └────────┬─────────┘
│
v
┌──────────────┐ ┌───────────────────────────────────────┐
│ FLAG │<────│ GET /api/orders/4 as haxor │
│ CAPTURED │ │ No ownership check — full PII leaked │
└──────────────┘ └───────────────────────────────────────┘
Application Architecture
| Component | Path | Description |
|---|---|---|
| Frontend | React SPA (main.54785890.js) | Pizza ordering UI |
| Backend | Express/Node.js | REST API, JWT auth |
| Database | SQLite (sequential IDs) | User and order storage |
| Auth | JWT HS256 | Token has {id, username, iat} — no role claim |
Exploitation Path
Step 1: Reconnaissance — Map the API Surface
Registered an account and intercepted traffic to enumerate all API endpoints. Key observations:
- JWT tokens contain
{id, username, iat}but no role — role is stored server-side - User IDs and order IDs are sequential integers
- Server returns
X-Powered-By: ExpressandAccess-Control-Allow-Origin: *on all responses
POST /api/register HTTP/1.1
Content-Type: application/json
{"username":"haxor","email":"haxor@test.com","password":"password123",
"full_name":"Hax Or","phone":"555-0001","address":"123 Hack St"}
Response included JWT and user object with id: 4 and role: "user".
Step 2: Test Admin Escalation (Dead End)
Attempted mass assignment to escalate to admin role on both registration and profile update:
PUT /api/profile HTTP/1.1
Authorization: Bearer <jwt>
Content-Type: application/json
{"role":"admin","is_admin":true,"admin":true,"userRole":"admin"}
All extra fields silently ignored. Admin endpoints (/api/admin/stats, /api/admin/users, /api/admin/orders) properly returned 403. This path was correctly locked down.
Step 3: Discover IDOR on Order Details
Created an order as haxor, then registered a second user victim1 and created an order as that user (order id=4). Switched back to haxor’s JWT and requested:
GET /api/orders/4 HTTP/1.1
Authorization: Bearer <haxor-jwt>
Server returned the full order belonging to victim1, including delivery address, phone number, and all order details. No ownership validation — just checks that the requester is authenticated.
Step 4: Capture Flag
The order detail response for another user’s order contained the flag:
bug{1eXwuTjS4MkMl2oWn3D1h1RFtabZuSLF}
Step 5: Discover Price Manipulation (Bonus Finding)
Tested whether the server validates prices by submitting an order with manipulated values:
POST /api/orders HTTP/1.1
Authorization: Bearer <jwt>
Content-Type: application/json
{"items":[{"pizza_id":1,"base_id":1,"sauce_id":1,"toppings":[1],
"unit_price":0,"quantity":1}],"total_price":0,
"delivery_address":"123 Free St","phone":"555-0000"}
Accepted. Also tested with unit_price: -100 and total_price: -100 — also accepted. The payment processing endpoint (POST /api/payment/process) similarly trusts client-supplied amount.
Flag / Objective Achieved
bug{1eXwuTjS4MkMl2oWn3D1h1RFtabZuSLF}
Obtained by accessing another user’s order via IDOR on GET /api/orders/:id.
Key Learnings
- Sequential IDs are enumerable — When endpoints use sequential integer IDs without ownership checks, the entire dataset is accessible by iterating through IDs.
- Role stored server-side can still be secure — Despite JWT having no role claim, the admin endpoints were properly protected. The vulnerability was elsewhere.
- Always test price fields on e-commerce apps — Server trusting client-supplied prices is a common and high-impact vulnerability in ordering/checkout flows.
- CORS
*amplifies other vulns — Wildcard CORS alone is often low-impact, but combined with IDOR it enables cross-origin data theft without user interaction beyond visiting a malicious page.
Failed Approaches
| Approach | Result | Why It Failed |
|---|---|---|
| Mass assignment (role=admin) on registration | Role stayed “user” | Server ignores unrecognized fields during registration |
| Mass assignment on profile PUT | Role stayed “user” | Profile update only accepts known profile fields |
| Direct access to /api/admin/* endpoints | 403 Forbidden | Proper server-side role check on admin routes |
Tools Used
| Tool | Purpose |
|---|---|
| Burp Suite / Browser DevTools | HTTP interception and request manipulation |
| curl | Direct API testing for IDOR and price manipulation |
Remediation
1. IDOR on Order Details (CVSS: 7.5 - High)
Issue: GET /api/orders/:id returns any order to any authenticated user without verifying ownership.
CWE Reference: CWE-639 - Authorization Bypass Through User-Controlled Key
// BEFORE (Vulnerable)
app.get('/api/orders/:id', authenticate, async (req, res) => {
const order = await db.getOrder(req.params.id);
res.json(order);
});
// AFTER (Secure)
app.get('/api/orders/:id', authenticate, async (req, res) => {
const order = await db.getOrder(req.params.id);
if (!order || order.user_id !== req.user.id) {
return res.status(404).json({ error: 'Order not found' });
}
res.json(order);
});
2. Client-Side Price Manipulation (CVSS: 8.1 - High)
Issue: Server trusts client-supplied unit_price and total_price in order creation. Payment processing also trusts client-supplied amount.
CWE Reference: CWE-602 - Client-Side Enforcement of Server-Side Security
// BEFORE (Vulnerable)
app.post('/api/orders', authenticate, async (req, res) => {
const { items, total_price } = req.body;
// Directly uses client-supplied prices
await db.createOrder({ user_id: req.user.id, items, total_price });
});
// AFTER (Secure)
app.post('/api/orders', authenticate, async (req, res) => {
const { items, delivery_address, phone } = req.body;
// Look up canonical prices server-side
const pricedItems = await Promise.all(items.map(async (item) => {
const pizza = await db.getPizza(item.pizza_id);
return { ...item, unit_price: pizza.price };
}));
const total_price = pricedItems.reduce(
(sum, i) => sum + i.unit_price * i.quantity, 0
);
await db.createOrder({ user_id: req.user.id, items: pricedItems, total_price });
});
3. Wildcard CORS (CVSS: 5.3 - Medium)
Issue: All endpoints return Access-Control-Allow-Origin: *, allowing any website to make authenticated cross-origin requests.
CWE Reference: CWE-942 - Permissive Cross-domain Policy with Untrusted Domains
// BEFORE (Vulnerable)
app.use(cors({ origin: '*' }));
// AFTER (Secure)
app.use(cors({
origin: 'https://cheesy-does-it.bugforge.io',
credentials: true
}));
OWASP Top 10 Coverage
- A01:2021 - Broken Access Control — IDOR on order details (no ownership check), wildcard CORS
- A04:2021 - Insecure Design — Client-side price enforcement with no server-side validation
References
- OWASP IDOR Prevention Cheat Sheet
- CWE-639: Authorization Bypass Through User-Controlled Key
- CWE-602: Client-Side Enforcement of Server-Side Security
- CWE-942: Permissive Cross-domain Policy
- OWASP Testing Guide: IDOR
Tags: #idor #price-manipulation #cors #broken-access-control #bugforge #api-security
Document Version: 1.0
Last Updated: 2026-03-23