# Insecure Design

Insecure Design is about flaws baked into the **architecture/logic** before any code was even written — the system does exactly what it was built to do, and that's the problem.

### The core distinction

*   **Implementation flaw:** "the login check was supposed to verify the password, but the code has a bug that skips it"
    
*   **Design flaw:** "the system was never designed to limit how many password attempts someone gets" — nothing's broken, it just was never designed with that protection in mind
    

### Common examples

*   **No rate limiting on sensitive actions** — password reset, login, OTP verification — allowing brute force simply because nobody designed a limit
    
*   **Trusting client-side logic for business rules** — e.g., a checkout flow where the *price* is calculated in JavaScript and just trusted by the server, rather than the server recalculating it independently
    
*   **Overly trusting workflows** — a multi-step process (like a purchase flow) where skipping a step (going straight to "confirm order" without "add payment") isn't prevented, because the design assumed users would always go in order
    
*   **Insufficient anti-automation** — signup forms, coupon codes, etc. with no CAPTCHA/rate limiting, designed assuming only "normal" human usage.
    

## Lab Scenario: Nimbus Electronics Shopping Cart

**The feature, as designed:**

```plaintext
POST /cart/add
{ "productId": 42, "quantity": 5 }
```

Server logic:

```javascript
function addToCart(productId, quantity) {
  const product = getProduct(productId);
  const lineTotal = product.price * quantity;
  cart.addItem(product, quantity, lineTotal);
  cart.total += lineTotal;
}
```

**What the designer assumed, unstated:** `quantity` will always be a positive whole number, because why would anyone add "-5 shirts" to a cart? Nobody writes a requirement document that says "quantity must be positive" because it feels too obvious to even need saying — and that's exactly the trap.

**The exploit, step by step:**

You have two items in your cart:

*   1x Laptop — $1000
    
*   You add: `{ "productId": 43, "quantity": -10 }` for a $50 accessory
    

The math runs exactly as written, faithfully, with no validation stopping it:

```plaintext
lineTotal = 50 * -10 = -500
cart.total = 1000 + (-500) = 500
```

**You now owe $500 for a $1000 laptop**, because the system happily subtracted money from your total — the code isn't buggy, `price * quantity` is completely correct arithmetic. The flaw is that nobody designed a rule saying quantities can't be negative, because it felt too obvious to write down.

**Depending on how checkout finalizes this,** you might even be able to push the total to **exactly $0, or negative** — some real-world versions of this exact bug have resulted in stores owing *customers* money at checkout, because nobody capped the total at a minimum of $0 either. Same root assumption failure, compounding.

## Why this specific type is so common and so easy to miss

they validate for *type* (is `quantity` a number?) but not for *real-world sense* (is this a number that makes sense in context?). `-10` passes every technical check — it's a valid integer, it fits in the database field, the multiplication doesn't error. Nothing about it looks "broken" to an automated test or a type-checker. It only looks wrong if you're thinking like a human about what a shopping cart *means*, not just what the code technically allows.

### Scenario 2: inconsistent handling of exceptional input

The idea: a system might handle normal input one way, and unusual/edge-case input in a subtly different way — and that difference in behavior itself becomes exploitable, even if neither path is individually "broken."

Registration with Duplicate Prevention This lab has a registration form and an account update / email change feature. The intended business rule: only one account per email address.

Normal behavior, as designed: Register with user@example.com → succeeds, account created Try to register again with the exact same user@example.com → correctly rejected: "email already in use" The exceptional input that breaks the assumption: The lab's actual vulnerable feature is the "update email" flow on your account. The intended rule is the same: you shouldn't be able to change your email to one that's already registered to someone else. Here's the twist that makes it "inconsistent handling": the validation check and the actual email-saving logic don't treat the input identically. Specifically, the duplicate-check might be case-sensitive or exact-match, while the actual update either doesn't re-validate, or handles a slightly malformed/edge-case version of the email differently than the check did. The real, official solve for this specific lab: you can update your email to include a second email address appended after a special separator character — many backend systems (in real implementations, things like extra @ symbols, or padding an email with attacker-chosen characters after a null byte or separator) get parsed inconsistently between validation (which checks the whole messy string and doesn't find a match, so it "passes") and the actual account update / notification logic (which might only read up to the first valid email portion, or normalize the input differently) — resulting in you effectively taking over another account because the validation layer and the execution layer disagreed about what the "real" input actually was.
