check-insecure-design
Insecure Design Security Check (A04:2021)
Analyze PHP code for insecure design patterns — architectural and business logic security flaws that cannot be fixed by implementation alone.
Detection Patterns
1. Missing Account Lockout
// VULNERABLE: No brute-force protection
class LoginController
{
public function login(Request $request): Response
{
$user = $this->userRepo->findByEmail($request->get('email'));
if ($user && password_verify($request->get('password'), $user->passwordHash())) {
return $this->createSession($user);
}
return new Response('Invalid credentials', 401);
// No attempt tracking! Attacker can try unlimited passwords
}
}
// CORRECT: Account lockout after N failures
class LoginController
{
private const int MAX_ATTEMPTS = 5;
private const int LOCKOUT_MINUTES = 15;
public function login(Request $request): Response
{
$email = $request->get('email');
if ($this->loginAttempts->isLocked($email)) {
return new Response('Account temporarily locked', 429);
}
$user = $this->userRepo->findByEmail($email);
if ($user && password_verify($request->get('password'), $user->passwordHash())) {
$this->loginAttempts->reset($email);
return $this->createSession($user);
}
$this->loginAttempts->record($email);
if ($this->loginAttempts->count($email) >= self::MAX_ATTEMPTS) {
$this->loginAttempts->lock($email, self::LOCKOUT_MINUTES);
}
return new Response('Invalid credentials', 401);
}
}
2. Missing Rate Limiting on Sensitive Endpoints
// VULNERABLE: No rate limiting on password reset
class PasswordResetController
{
public function requestReset(Request $request): Response
{
$email = $request->get('email');
$this->resetService->sendResetLink($email);
return new Response('Reset link sent', 200);
// Attacker can spam reset emails, enumerate users
}
}
// VULNERABLE: No rate limiting on API key generation
class ApiKeyController
{
public function generate(Request $request): Response
{
return new Response($this->apiKeyService->generate());
// Unlimited key generation
}
}
3. TOCTOU (Time-of-Check-Time-of-Use) Race Condition
// VULNERABLE: Check and use are separate operations
class InventoryService
{
public function purchase(ProductId $id, int $quantity): void
{
$stock = $this->inventory->getStock($id);
if ($stock >= $quantity) { // CHECK
// Another request could reduce stock here!
sleep(1); // Simulates processing time
$this->inventory->reduce($id, $quantity); // USE — may oversell!
}
}
}
// CORRECT: Atomic check-and-reduce
class InventoryService
{
public function purchase(ProductId $id, int $quantity): void
{
$reduced = $this->inventory->reduceIfAvailable($id, $quantity);
// Atomic operation: UPDATE stock SET quantity = quantity - ? WHERE id = ? AND quantity >= ?
if (!$reduced) {
throw new InsufficientStockException();
}
}
}
4. Missing Business Logic Validation
// VULNERABLE: No business rules on discount
class DiscountService
{
public function applyDiscount(Order $order, int $percent): void
{
$order->setDiscount($percent); // No max limit! 100%? 200%?
}
}
// VULNERABLE: Price manipulation
class CartController
{
public function updateItem(Request $request): Response
{
$item = $this->cart->getItem($request->get('itemId'));
$item->setPrice($request->get('price')); // Client sends price!
}
}
// VULNERABLE: Negative quantity
class OrderService
{
public function addItem(OrderId $id, int $quantity): void
{
$this->order->addItem($id, $quantity); // Negative = credit?
}
}
5. Missing CAPTCHA on Automated Endpoints
// VULNERABLE: Form without bot protection
class RegistrationController
{
public function register(Request $request): Response
{
// No CAPTCHA — bots can mass-register
$user = User::create(
email: $request->get('email'),
password: $request->get('password'),
);
$this->userRepo->save($user);
}
}
// VULNERABLE: Contact form without protection
class ContactController
{
public function submit(Request $request): Response
{
// No CAPTCHA — spam submissions
$this->mailer->send($request->get('message'));
}
}
6. Insecure Direct Object Reference by Design
// VULNERABLE: Sequential IDs expose information
class UserController
{
public function show(int $id): Response
{
// Enumerable: /users/1, /users/2, /users/3...
return new Response($this->userRepo->find($id));
}
}
// CORRECT: Use UUIDs
class UserController
{
public function show(string $id): Response
{
return new Response($this->userRepo->find(new UserId($id)));
// /users/550e8400-e29b-41d4-a716-446655440000
}
}
Grep Patterns
# Login without lockout
Grep: "password_verify|authenticate|login" --glob "**/*Controller*.php"
Grep: "loginAttempts|failedAttempts|lockout|isLocked" --glob "**/*.php"
# Password reset without rate limiting
Grep: "resetPassword|forgotPassword|sendResetLink" --glob "**/*.php"
Grep: "RateLimit|throttle|rateLimiter" --glob "**/*.php"
# TOCTOU patterns
Grep: "getStock|getBalance|checkAvailability" --glob "**/*.php"
Grep: "reduceIfAvailable|atomicDecrement|FOR UPDATE" --glob "**/*.php"
# Client-sent prices
Grep: "request->get\(['\"]price|request->get\(['\"]amount" --glob "**/*Controller*.php"
# Missing CAPTCHA
Grep: "captcha|recaptcha|hcaptcha|turnstile" --glob "**/*.php"
Grep: "register|signup|contact" --glob "**/*Controller*.php"
# Sequential IDs
Grep: "function show\(int \$id\)|function get\(int \$id\)" --glob "**/*Controller*.php"
Severity Classification
| Pattern | Severity |
|---|---|
| Missing account lockout | 🔴 Critical |
| TOCTOU race condition | 🔴 Critical |
| Client-controlled pricing | 🔴 Critical |
| No rate limiting on auth endpoints | 🟠 Major |
| Missing CAPTCHA on registration | 🟠 Major |
| Sequential enumerable IDs | 🟡 Minor |
Output Format
### Insecure Design: [Description]
**Severity:** 🔴/🟠/🟡
**Location:** `file.php:line`
**CWE:** CWE-840 (Business Logic Errors)
**OWASP:** A04:2021 — Insecure Design
**Issue:**
[Description of the design-level security flaw]
**Attack Scenario:**
[How an attacker exploits this design flaw]
**Code:**
```php
// Insecure design
Fix:
// Secure by design
More from dykyi-roman/awesome-claude-code
psr-overview-knowledge
PHP Standards Recommendations (PSR) overview knowledge base. Provides comprehensive reference for all accepted PSRs including PSR-1,3,4,6,7,11,12,13,14,15,16,17,18,20. Use for PSR selection decisions and compliance audits.
22detect-code-smells
Detects code smells in PHP codebases. Identifies God Class, Feature Envy, Data Clumps, Long Parameter List, Long Method, Primitive Obsession, Message Chains, Inappropriate Intimacy. Generates actionable reports with refactoring recommendations.
15clean-arch-knowledge
Clean Architecture knowledge base. Provides patterns, antipatterns, and PHP-specific guidelines for Clean Architecture and Hexagonal Architecture audits.
15ddd-knowledge
DDD architecture knowledge base. Provides patterns, antipatterns, and PHP-specific guidelines for Domain-Driven Design audits.
14testing-knowledge
Testing knowledge base for PHP 8.4 projects. Provides testing pyramid, AAA pattern, naming conventions, isolation principles, DDD testing guidelines, and PHPUnit patterns.
12bug-root-cause-finder
Root cause analysis methods for PHP bugs. Provides 5 Whys technique, fault tree analysis, git bisect guidance, and stack trace parsing.
12