← Back to all labs
OWASP A06 · LAB ENVIRONMENT

Insecure Design

Insecure Design happens when security controls that should have been designed in from the start — like rate limiting and account lockout — are simply missing, no amount of clean code can patch a flawed blueprint. Try the interactive playground below to see how a password-reset flow with no rate limiting falls to automated guessing in seconds.

OWASP Top 10 · 2025 · A06 — Insecure Design

Insecure Design: When the Blueprint Itself Is the Vulnerability

Insecure design isn’t a coding bug you can patch — it’s a missing or inadequate security control baked into how a feature was planned, before a single line of code was written. Think: a password-reset flow that never considered limiting guesses, business logic that trusts whatever the client sends, or a checkout process with no thought given to abuse cases. The code can be written “correctly” and still be dangerously insecure, because the design never accounted for an attacker’s perspective.
Scenario: account recovery requires a 4-digit reset code sent to the user.
Question: what happens when someone just tries every combination?
Rate Limiting & Lockout OFF

Attacker / Tester Console

Account active — reset code required
Attempts made 0
System ready. Awaiting reset-code attempts…

What’s actually happening (backend view)

This is what a real backend engineer would see in logs — visible here for teaching purposes only. In production, none of this would be shown to the client.

  • Valid reset code: ???? (hidden until revealed)
  • Total possible 4-digit codes: 10,000
  • Attempt limit: none configured
  • Lockout policy: none configured
⚠ Vulnerable design
  • Reset credential is a 4-digit numeric code — only 10,000 possible combinations.
  • No limit on the number of attempts a single user or IP can make.
  • No lockout, no delay, no CAPTCHA, no alerting on repeated failures.
  • Design assumption: “no one will bother guessing.” Guessable by script in seconds.
  • Client-side only feels secure — server never enforces any abuse limits.
✓ Secure design
  • Reset credential is a long random token (e.g. 32+ chars) sent via a trusted channel.
  • Rate limiting per account, per IP, and per session on every reset attempt.
  • Exponential backoff + account lockout after a small number of failures (e.g. 5).
  • Alerting / logging triggered on repeated-failure patterns for security review.
  • Threat-modeled at design time: “assume this endpoint will be attacked.”
Insecure design flaws can’t be fixed with a quick patch — the feature has to be rethought from the ground up, because the missing control (like rate limiting) was never part of the plan. Unlike a bug in otherwise-sound logic, this is the logic working exactly as designed — the design itself just never considered how an attacker would abuse it.
  • Threat-model during design, not after launch — ask “how would this be abused?” for every sensitive feature before it’s built.
  • Avoid short numeric codes for anything security-sensitive; use long, random, high-entropy tokens instead.
  • Enforce rate limiting, lockout, and exponential backoff server-side on login, reset, and other sensitive actions.
  • Apply secure-by-design principles (least privilege, defense in depth, fail securely) as requirements, not afterthoughts.
  • Test abuse cases, not just happy paths — include brute-force, race-condition, and logic-abuse scenarios in QA and pen testing.