Insecure Design
4) Insecure Design
What it is (simple)
Insecure Design means the system idea/workflow is unsafe, even if code is clean.
This is different from a coding mistake:
- Coding bug: “we wrote this check wrong.”
- Insecure design: “we never planned this check/control at all.”
So the app behaves “as designed,” but the design itself is weak.
Easy mental model
Think of building a house:
- Code bugs = broken lock on the door.
- Insecure design = no door in the first place.
Common insecure design examples
- No rate limit on login or OTP verification.
- Password reset flow does not expire tokens quickly.
- Money transfer flow allows negative values or replay.
- API allows changing account owner because workflow trusts client too much.
- Admin actions need no second confirmation or step-up auth.
- Multi-tenant app has no tenant isolation strategy at design level.
Step-by-step attack example (password reset design flaw)
- App has “Forgot password.”
- It sends reset token by email.
- Token is valid for 7 days and can be reused many times.
- Attacker steals old email/token once.
- Days later attacker reuses same token.
- Account is taken over.
Problem is not just one line of code. Main problem: token lifecycle was designed poorly (long lifetime + reusable).
Why this happens
- Team focuses on features first, abuse later.
- No threat modeling during planning.
- No “abuse-case” testing.
- Assumption: “authenticated user = safe user.”
- Security requirements were never written.
Tricky concepts explained
1) Threat modeling
Threat modeling means asking early:
- What are we protecting?
- Who can attack?
- Where can they enter?
- What can go wrong in each flow?
It is a design exercise before coding.
2) Use case vs abuse case
- Use case: how normal users should use a feature.
- Abuse case: how attackers could misuse the same feature.
If you design only use cases, attackers will find the missing side.
3) Trust boundary
A trust boundary is where data moves from less trusted to more trusted zones.
Example:
- Internet user input -> backend API.
- Backend API -> internal admin service.
At each boundary, you must validate, authorize, and constrain actions.
4) Defense in depth
Never depend on one control only.
Example for transfer endpoint:
- Auth check
- Authorization check
- Input/business-rule validation
- Rate limit
- Fraud detection
- Logging/alerting
If one control fails, others still reduce damage.
How to prevent insecure design (practical sequence)
- Define security requirements per feature before development.
- Do threat modeling for critical workflows (auth, payments, admin, data export).
- Write abuse cases next to user stories.
- Design compensating controls (rate limits, lockouts, step-up auth, confirmations).
- Use secure design patterns/reference architectures.
- Add architecture/security review gates before release.
- Test business logic, not just technical vulnerabilities.
- Revisit design after incidents and near-misses.
Detection (important reality)
Scanners alone cannot fully detect insecure design.
You need:
- Architecture review
- Threat modeling workshops
- Business logic penetration testing
- Red-team style workflow abuse tests
Quick junior checklist
- Can an attacker automate this flow cheaply?
- What happens if a user repeats requests fast?
- Can old tokens/sessions be reused?
- Can one user affect another user’s assets?
- Is there step-up auth for high-risk actions?
- If one control fails, what backup control exists?
Business impact
- Account takeover
- Fraud and financial loss
- Large-scale abuse by bots
- Hard-to-fix systemic risk (because architecture must change)