BugForge — 2026.03.23

Cheesy Does It: IDOR + Price Manipulation

BugForge Broken Access Control medium

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

  1. 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.

  2. Client-Side Price Manipulation (CWE-602: Client-Side Enforcement of Server-Side Security) — Server trusts client-supplied unit_price and total_price in POST /api/orders. Also trusts client-supplied amount in POST /api/payment/process. Accepted $0 and negative amounts.

  3. 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: Express and Access-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


Tags: #idor #price-manipulation #cors #broken-access-control #bugforge #api-security Document Version: 1.0 Last Updated: 2026-03-23

#IDOR #price-manipulation #PII-exposure #CORS