Unrestricted Access to Sensitive Business Flows
Theory
API6 Unrestricted Access to Sensitive Business Flows is new to the OWASP API Top 10 in 2023. Unlike the other authentication/authorization categories, this one is about legitimate functionality being misused at scale. The endpoint works exactly as designed β the problem is that there are no business-logic controls preventing automated abuse.
What Makes a Business Flow "Sensitive"
- Inventory / purchase flows β a scalper bot buys all limited-edition items the moment they go on sale; resells at 10x price
- Voucher / gift card checking β bulk-checking thousands of codes per minute to find valid unredeemed cards
- User enumeration at scale β calling a "check if email is registered" or "check if username exists" endpoint millions of times to build targeted phishing lists
- Price scraping β competitors scrape all product prices every hour to undercut dynamically
- Referral abuse β creating thousands of fake accounts to harvest referral bonuses
- Free tier abuse β creating unlimited free accounts, each with its own free resource allocation
The Sneaker Bot Problem
# A limited-edition sneaker drops at 10:00 AM. 10,000 units available.
# A bot pre-loads all required data, monitors for the drop, and fires:
for _ in range(10000):
r = requests.post("/api/v1/orders",
headers={"Authorization": f"Bearer {token}"},
json={"product_id": SNEAKER_ID, "quantity": 1})
if r.status_code == 201:
orders.append(r.json())
# In < 1 second, the bot buys all 10,000 units.
# Human users receive "out of stock" immediately after the drop.
# No authentication failure β every request uses a valid token and real account.
Gift Card / Voucher Enumeration
# VULNERABLE β no rate limit on code checking; no limit on batch size
@app.post("/api/v1/giftcards/check")
async def check_giftcards(request: Request):
body = await request.json()
codes = body.get("codes", []) # attacker sends 10,000 codes in one request
results = []
for code in codes:
card = db.get_giftcard(code)
results.append({"code": code, "valid": bool(card), "value": card.value if card else 0})
return results
# Attack: brute-force gift card numbers
for i in range(10000):
code = f"RATC-{i:04d}-GIFT"
r = requests.post("/api/v1/giftcards/check", json={"codes": [code]})
if r.json()[0]["valid"]:
print(f"Valid card: {code}")
Fixed Code
# FIXED β rate limiting + batch size cap + single-code-only enforcement
from slowapi import Limiter
limiter = Limiter(key_func=get_remote_address)
@app.post("/api/v1/giftcards/check")
@limiter.limit("5/minute") # severely throttle this endpoint
async def check_giftcards(request: Request, body: GiftCardCheckRequest, user = Depends(get_current_user)):
if len(body.codes) > 1: # allow only one code per request
raise HTTPException(400, "Only one code per request")
code = body.codes[0]
card = db.exec(select(GiftCard).where(GiftCard.code == code)).first()
# Timing-safe response: same delay regardless of whether code is valid
await asyncio.sleep(random.uniform(0.1, 0.3)) # prevent timing-based enumeration
return {"valid": bool(card)}
Real-World Examples
- Nike / Adidas SNKRS (2019βpresent) β Sneaker bots routinely buy out entire drops within milliseconds. Nike's SNKRS app introduced CAPTCHA and randomised checkout timing; bots adapted within days.
- Airbnb (2018) β A researcher discovered the coupon check endpoint had no rate limiting; valid coupon codes could be enumerated by brute-force in minutes. $5,000 bounty.
- Twitter (2017) β Phone number lookup endpoint with no rate limit allowed enumeration of registered phone numbers at scale
How to Fix β Checklist
- Rate limiting specific to business flows β gift card checks: 5/minute; purchase: 10/minute; account creation: 3/hour per IP
- Batch size caps β every endpoint accepting arrays should have a strict maximum count at the schema level
- Device fingerprinting + behavioural analysis β detect inhuman request patterns (identical headers, sub-millisecond timing) and require CAPTCHA or block
- Inventory locks β hold inventory reservation for a limited time window; release if checkout isn't completed
- Queue flows for high-demand events β virtual waiting room (e.g. Cloudflare Waiting Room) serialises access during drops
- Account age and trust scoring β newly created accounts face stricter limits; purchasing requires email verification or phone verification
Challenge 1
Bulk Gift Card Checking β Enumerate Valid Codes
The gift card validation endpoint accepts a list of codes with no size limit. Check hundreds of codes in a single request to enumerate valid ones.
Hint
POST /api/v1/giftcards/check with {"codes": ["RATC-0000-GIFT", ..., "RATC-FLAG-API6"]}