Allowlist vs Blocklist
debt(d5/e5/b5/t6)
Closest to 'specialist tool catches it' (d5). The term's detection_hints list semgrep as the tool, which can identify blocklist patterns like strpos($input,'script') or preg_replace blocking specific patterns instead of allowlisting. This is a specialist SAST tool, not a default linter, so d5 fits. A general PHP linter won't flag this — you need semgrep rules configured for the pattern.
Closest to 'touches multiple files / significant refactor in one component' (e5). While the quick_fix sounds simple ('use allowlists not blocklists'), in practice converting blocklist-based validation to allowlist-based validation often requires touching multiple validation points across a codebase — file upload handlers, input sanitizers, redirect URL checks, etc. Each blocklist instance needs a replacement allowlist with carefully defined permitted values. Not architectural rework, but definitely more than a one-line fix in most real codebases.
Closest to 'persistent productivity tax' (b5). The allowlist vs blocklist choice applies across web, api, and cli contexts and affects every validation point in the system. Choosing blocklist as a pattern creates ongoing maintenance burden — every new attack vector requires updating the blocklist. It's a cross-cutting validation philosophy that shapes how all input handling works, but it doesn't quite define the system's entire architecture (b7). It's a persistent tax on security-related development across many work streams.
Closest to 'notable trap' (t5), +1 to t6. The misconception states 'A blocklist is as secure as an allowlist for input validation' — this is a well-documented gotcha that most developers eventually learn, but it contradicts the intuitive approach many developers take (blocking known-bad seems logical and equivalent to allowing known-good). The trap is worse than a simple documented gotcha (t5) because blocklists feel intuitively complete — developers genuinely believe they've covered all cases. However, it doesn't quite reach t7 (contradicts how a similar concept works elsewhere) since the concept itself is straightforward once explained.
Also Known As
TL;DR
Explanation
A blocklist (blacklist) attempts to enumerate known bad inputs and reject them. It will always be incomplete — attackers find encodings, bypasses, and new attack vectors that were not anticipated. An allowlist (whitelist) defines exactly what is acceptable and rejects everything else. Allowlists are inherently more secure because you control the entire space of valid input. When validating file extensions, redirect targets, HTML tags, or system commands — always use an allowlist.
Diagram
flowchart TD
INPUT[User Input] --> APPROACH{Validation approach}
APPROACH -->|Blocklist| BLOCK_LIST[Check against known bad<br/>reject blacklisted values]
APPROACH -->|Allowlist| ALLOW_LIST[Check against known good<br/>reject anything not in list]
BLOCK_LIST --> BYPASS[Attacker finds bypass<br/>new attack vector not in list]
ALLOW_LIST --> SAFE2[Only known safe values pass<br/>unknown input rejected by default]
subgraph Examples
BL_EX[Blocklist: remove script tags<br/>attacker uses SVG onload]
AL_EX[Allowlist: only accept a b p tags<br/>anything else rejected]
end
style BLOCK_LIST fill:#f85149,color:#fff
style ALLOW_LIST fill:#238636,color:#fff
style BYPASS fill:#f85149,color:#fff
style SAFE2 fill:#238636,color:#fff
Common Misconception
Why It Matters
Common Mistakes
- Using a blocklist for file upload validation — attackers find file types not on the list.
- Allowlists that are too broad — 'any image type' vs 'jpeg, png, gif specifically'.
- Not normalising input before allowlist checking — %2e%2e%2f passes a check for '../'.
- Blocklisting user-agent or IP ranges for security — too easy to spoof or rotate.
Avoid When
- Blocklist-only input validation for security-critical paths — attackers find bypasses; allowlists are safer.
- Allowlists so strict they break legitimate input — test with real-world edge cases before deploying.
- Maintaining a blocklist of known-bad values for SQL injection or XSS — use parameterised queries and output encoding instead.
When To Use
- Always prefer allowlists for security validation — define what is allowed, reject everything else.
- Blocklists for UX filtering like profanity or spam signals — correctness matters less than security here.
- Allowlists for file upload MIME types and extensions — never trust user-supplied content type alone.
- Allowlists for redirect URLs — open redirect vulnerabilities arise from blocklist-only approaches.
Code Examples
// Blocklist — attacker uploads .php7, .phtml, .phar:
$blocked = ['php', 'exe', 'sh'];
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
if (in_array($ext, $blocked)) die('Blocked');
// Allowlist — only explicitly permitted:
$allowed = ['jpg', 'jpeg', 'png', 'gif'];
if (!in_array($ext, $allowed)) die('Not allowed');
// Allowlist — permit known-good; deny everything else (safer)
$allowed = ['jpeg', 'png', 'webp', 'gif'];
$ext = strtolower(pathinfo($_FILES['img']['name'], PATHINFO_EXTENSION));
if (!in_array($ext, $allowed, true)) abort(415);
// Blocklist — deny known-bad; allow everything else (fragile)
$blocked = ['php', 'php3', 'php4', 'phtml', 'phar'];
// Attackers find new extensions you forgot to block (.php5, .shtml)
// Always prefer allowlists for:
// - File extensions, MIME types
// - Redirect URLs (domain allowlist)
// - HTML attributes (HTMLPurifier allowlist)
// - User roles, permissions
// Blocklists for:
// - WAF rule augmentation (block known attack patterns)
// - IP reputation (block known-bad IPs)
// — but never as the only defence