Order Status Forced Browsing: Finding Hidden Fulfillment Endpoints
Forced browsing is guessing URLs the UI never links. Order status systems are full of them: /admin/orders/123, /fulfillment/pack/123, /api/internal/shipping-label?orderId=123. Shoppers get a pretty tracking page. Staff tools sit one path sideways.
If those paths rely on obscurity—or check authz poorly—you read or mutate someone else's fulfillment state.
Build a path list
From your own order confirmation, collect IDs: orderId, number, trackingToken, shipmentId. Then expand:
/orders/{id},/orders/{id}/status,/orders/{id}/cancel/admin/orders/{id},/manage/orders/{id},/staff/fulfillment/{id}/api/v1/orders/{id}versus/api/internal/orders/{id}- Warehouse verbs:
pack,ship,refund,mark-delivered
Crawl JS bundles for route tables and status enums. markDelivered in a webpack chunk is a gift even when the button is role-gated in React.
Try HTTP methods the UI skips. A GET page might be locked while PATCH /api/orders/ID with {"status":"delivered"} works for any logged-in user.
Sitemap, robots, and old mobile deep links expose staff paths too. Allow: /internal/ in robots.txt has aged poorly and still appears.
GraphQL helps and hurts. Introspect for updateOrderStatus, fulfillOrder, or createShippingLabel. Mutations missing from the storefront still resolve if the gateway only checks "logged in."
Horizontal then vertical
Horizontal: order A while authenticated as buyer B. Vertical: buyer calling admin status. Use two accounts you own. Swap only the object ID first; do not spray sequential IDs across the whole shop until you know guesses are in scope and rate-safe.
Unsigned tracking tokens in email links deserve a special look. If /track?token=HEX is the only secret, test whether tokens are predictable or reusable across orders. Token ORB (order resource browsing) still counts as forced browsing when paths are unlinked.
Numeric order numbers that increment are classic. UUID order IDs reduce guessing but do not fix missing authz on /admin/orders/{uuid}. Test both identifier styles if the API accepts either.
Mutations beat reads
Reading another user's shipping city can be P2/P3. Setting their order to cancelled or delivered without payment capture is clearer impact—do it only on your second account's order. Refunds and label downloads need extra care; avoid generating carrier charges.
Export endpoints (/orders/{id}/invoice.pdf, CSV dumps) often share the same IDOR. A PDF with address lines is enough PII impact without changing status.
Support-tool proxies are sneaky: /helpdesk/order-lookup?q= may return full records for any number once you are a low-privilege agent—or once you forge a role cookie the SPA thinks it needs.
Anonymous access is the worst case. Log out and retry the tracking or invoice URL. A 200 with PII and no token means the path was never meant to be public—say that bluntly.
Close the report
Include the unlinked URL, auth context (anonymous, user, admin cookie), the victim order owned by you, and the before/after status. Recommend consistent authorization on every order identifier, no reliance on hidden admin paths, short-lived signed tracking links, and method-level checks that match UI roles.
Forced browsing feels old-school because it is. Ecommerce staff tools still ship with predictable URLs and half-finished authz. Walk the paths.