ankur@sec:~$

$ cat owasp/a06.md

A06:2025

Insecure Design

The code does exactly what it was designed to do - and the design is the problem.

## 1 · why it happens

You cannot fix these with a library. A checkout that trusts the price sent by the browser, a coupon that can be applied twice if two requests arrive together, a password reset with no rate limit - each is a missing rule in the design.

The developer's best tool here is asking "what if?" while designing: what if the user sends this twice, out of order, with a negative number, a thousand times a second?

# JavaScript

✗ vulnerable
app.post('/checkout', async (req, res) => {
  // price comes from the client
  await charge(req.user, req.body.items, req.body.total);
});
✓ fixed
app.post('/checkout', async (req, res) => {
  const items = await loadItems(req.body.itemIds);   // prices from the DB
  const total = items.reduce((s, i) => s + i.price * i.qty, 0);
  if (items.some((i) => i.qty < 1)) return res.sendStatus(400);
  await charge(req.user, items, total);
});

# C#

✗ vulnerable
// Two parallel requests can both pass this check
var coupon = await _db.Coupons.FindAsync(code);
if (!coupon.Used)
{
    ApplyDiscount(order, coupon);
    coupon.Used = true;
    await _db.SaveChangesAsync();
}
✓ fixed
// Atomic: only one request can flip Used from false to true
var updated = await _db.Coupons
    .Where(c => c.Code == code && !c.Used)
    .ExecuteUpdateAsync(s => s.SetProperty(c => c.Used, true));
if (updated == 1) ApplyDiscount(order, code);

## 2 · how attackers find it from outside

public sourcewhat it tells them
Public docs & help pagesHow your workflows work (refunds, coupons, invites) - the logic to abuse.
Mobile app / JS bundleClient-side checks (price, limits) that the server may not repeat.

→ all OSINT sources · run them on yourself

## 3 · how it's abused

⚠ Recon your own assets, or targets you have written permission to test. Passive OSINT reads public data, but using it to target someone else's systems can still be illegal or against their terms. Examples on this site use example.com placeholders.

{"itemId": 42, "qty": -1}

Business logic: a negative quantity turns a purchase into a refund.

20 × POST /redeem-coupon in parallel

Race condition: all requests check "not used yet" before any of them marks it used.

10,000 × POST /verify-otp

No rate limit: a 6-digit code can be brute-forced.

Payload examples adapted from PayloadsAllTheThings (MIT, © Swissky). Full lists:Business Logic Errors · Race Condition · Brute Force Rate Limit

## 4 · fix

## 5 · detect

test it

ZAP

Open-source web app scanner and proxy. The baseline scan is safe for CI.

authorized targets only

Official description: OWASP A06:2025 Insecure Design