Weakness reference
CWE-184

Incomplete Blocklist

An incomplete blocklist is a security control that attempts to block dangerous or unwanted values, but fails to account for all variants or bypass techniques…

01Summary

An incomplete blocklist is a security control that attempts to block dangerous or unwanted values, but fails to account for all variants or bypass techniques. Attackers can circumvent the protection by using unlisted alternatives—different encodings, case variations, or synonym values—that achieve the same malicious goal. This weakness is particularly dangerous because it creates a false sense of security while leaving real vulnerabilities open.

02How It Happens

Blocklists work by comparing user input or system behavior against a predefined set of forbidden values. The assumption is that if a value isn't on the list, it's safe. However, this approach is fundamentally fragile: attackers can often achieve the same outcome using variations the blocklist author didn't anticipate. Common bypass techniques include URL encoding, Unicode normalization, case manipulation, null bytes, alternative syntax, or synonym functions. For example, a blocklist blocking the string "admin" might miss "Admin", "ADMIN", "%61dmin" (URL-encoded), or "0x61dmin" (hex-encoded). The more complex the attack surface, the more variants exist, and the harder it becomes to enumerate them all.

03Real-World Impact

Incomplete blocklists have enabled SQL injection, cross-site scripting (XSS), command injection, and authentication bypass attacks across countless applications. A blocklist intended to prevent SQL keywords might miss encoded variants, allowing an attacker to extract sensitive data. A filter meant to block malicious file uploads might be bypassed using double extensions or case variations, leading to remote code execution. Because the control appears to be in place, developers and security teams may not implement additional layers of defense, leaving the application fully exposed once the blocklist is circumvented.

04Vulnerable & Fixed Patterns

Vulnerable pattern
# Blocklist approach: attempt to block dangerous keywords
blocked_keywords = ["drop", "delete", "exec", "system"]

def is_safe_query(user_input):
    for keyword in blocked_keywords:
        if keyword in user_input.lower():
            return False
    return True

# Attacker bypasses with encoding or case variation
user_query = "Dr0p table users"  # Numeric substitution
if is_safe_query(user_query):
    execute_query(user_query)  # Vulnerable: bypassed the blocklist

Why it's vulnerable:
The blocklist only checks for exact lowercase matches. An attacker can use case variation, numeric substitution, or encoding to bypass the filter while the underlying system still interprets the malicious command.

Fixed pattern
# Allowlist approach: only permit known-safe patterns
import re

def is_safe_query(user_input):
    # Only allow alphanumeric, spaces, and specific safe characters
    if not re.match(r'^[a-zA-Z0-9\s_,]+$', user_input):
        return False
    return True

# Alternatively, use parameterized queries (best practice)
import sqlite3
conn = sqlite3.connect(':memory:')
cursor = conn.cursor()
# User input is passed as a parameter, not concatenated
cursor.execute("SELECT * FROM users WHERE id = ?", (user_input,))
Vulnerable pattern
<?php
// Blocklist of dangerous file extensions
$blocked_extensions = array('exe', 'sh', 'bat', 'cmd');

function is_safe_upload($filename) {
    $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
    return !in_array($ext, $blocked_extensions);
}

// Attacker bypasses with double extension or null byte
$uploaded_file = "shell.php.exe";  // Bypasses: only checks final extension
if (is_safe_upload($uploaded_file)) {
    move_uploaded_file($_FILES['file']['tmp_name'], "/uploads/" . $uploaded_file);
}
?>

Why it's vulnerable:
The blocklist only checks the final file extension. An attacker can use double extensions, null bytes, or case variations to bypass the filter and upload executable code.

Fixed pattern
<?php
// Allowlist approach: only permit known-safe extensions
$allowed_extensions = array('jpg', 'jpeg', 'png', 'gif', 'pdf');

function is_safe_upload($filename) {
    $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
    return in_array($ext, $allowed_extensions);
}

// Validate MIME type as well
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mime = finfo_file($finfo, $_FILES['file']['tmp_name']);
$allowed_mimes = array('image/jpeg', 'image/png', 'image/gif', 'application/pdf');

if (is_safe_upload($_FILES['file']['name']) && in_array($mime, $allowed_mimes)) {
    move_uploaded_file($_FILES['file']['tmp_name'], "/uploads/" . basename($_FILES['file']['name']));
}
?>

05Prevention Checklist

Use allowlists instead of blocklists.
Define what is permitted, not what is forbidden. Allowlists are far easier to maintain and reason about.
Parameterize queries and commands.
For SQL, use prepared statements with bound parameters. For shell commands, use safe APIs that don't invoke a shell interpreter.
Validate input format and type.
Check that input matches an expected pattern (regex, length, character set) before processing.
Encode output appropriately.
Even if input validation passes, encode output for the context (HTML, URL, JavaScript) to prevent injection.
Use multiple layers of defense.
Don't rely on a single filter. Combine input validation, parameterization, output encoding, and principle of least privilege.
Test bypass techniques.
Actively test your controls against case variation, encoding, null bytes, and other common bypass methods.

06Signs You May Already Be Affected

Review your application logs for unusual input patterns: repeated requests with encoded characters, case variations of known attack keywords, or requests that succeed despite appearing to violate your filters. Check for unexpected file uploads with double extensions or unusual MIME types. If you have a blocklist-based security control in place, audit it against known bypass techniques and consider whether an allowlist would be more appropriate.

07Related Recent Vulnerabilities