Improper Filtering of Special Elements

Description

Improper Filtering of Special Elements is an input validation vulnerability where software receives data from an upstream component but fails to filter or incorrectly filters special characters or elements before passing the data to a downstream component. Special elements include characters that have syntactic meaning in the target context, such as path separators, command delimiters, SQL operators, XML/HTML tags, or escape sequences. When filtering is absent or incomplete, attackers can inject malicious content that is interpreted as commands or markup by downstream processors.

Risk

Improper filtering enables a wide range of injection attacks depending on the downstream context. Path traversal becomes possible when directory separators (../) aren't properly filtered. Command injection occurs when shell metacharacters pass through. SQL injection results from unfiltered quotes and SQL keywords. XSS attacks succeed when HTML/JavaScript elements aren't neutralized. The risk is that attackers can break out of the intended data context to execute commands, access unauthorized resources, or manipulate application behavior. Incomplete filtering (like removing only single occurrences) is particularly dangerous as it gives false confidence while remaining exploitable.

Solution

Implement comprehensive input filtering or encoding appropriate for the target context. Use allowlist validation when possible—accept only known-good characters. If filtering special elements, ensure all instances are handled (use global replacement). Prefer output encoding over input filtering—encode data at the point of use for the specific output context. Use parameterized queries for SQL, DOM methods for HTML, and proper escaping for shell commands. Layer defenses: combine input validation, output encoding, and context-appropriate APIs. Test filtering implementations with various bypass techniques including double-encoding, alternate encodings, and recursive patterns.

Common Consequences

ImpactDetails
IntegrityScope: Integrity

Unexpected State - Application reaches unintended state due to improperly filtered input affecting control flow or data.
ConfidentialityScope: Confidentiality

Read Application Data - Path traversal or injection attacks may expose sensitive data.
IntegrityScope: Integrity

Execute Unauthorized Code - Command or code injection becomes possible when filtering fails.

Example Code

Vulnerable Code

# Vulnerable: Only removes first occurrence of "../"
#!/usr/bin/perl

my $username = GetUntrustedInput();

# Vulnerable: Missing /g modifier - only removes first occurrence
$username =~ s/\.\.\///;

my $filename = "/home/user/" . $username;
open(FILE, $filename);  # Path traversal possible!

# Attack: Input "....//....//etc/passwd"
# After single replacement: "../../../etc/passwd"
// Vulnerable: Incomplete filtering of SQL special chars
<?php
function vulnerable_escape($input) {
    // Vulnerable: Only escapes single quote, not double quote or backslash
    $filtered = str_replace("'", "''", $input);
    return $filtered;
}

$username = vulnerable_escape($_GET['username']);
$query = "SELECT * FROM users WHERE name = '$username'";
// Still vulnerable to injection via double quotes or backslash

// Attack: Input: \" OR 1=1 --
// Vulnerable: Filtering only some HTML tags
public class VulnerableFilter {
    public String filterXSS(String input) {
        // Vulnerable: Only filters <script> tags
        String filtered = input.replaceAll("<script>", "")
                              .replaceAll("</script>", "");
        return filtered;
    }
}

// Attack: <img src=x onerror=alert(1)>
// Attack: <SCRIPT>alert(1)</SCRIPT> (case variation)
// Attack: <scr<script>ipt>alert(1)</scr</script>ipt> (nested)
# Vulnerable: Single-pass replacement allows bypass
def vulnerable_filter_traversal(path):
    # Vulnerable: Single replacement - nested sequences survive
    filtered = path.replace('../', '')
    return filtered

# Attack: "....//....//etc/passwd"
# After filtering: "../../etc/passwd" - traversal still works!
// Vulnerable: Filtering null bytes but not encoded forms
void vulnerable_filter_null(char* input, char* output) {
    int j = 0;
    for (int i = 0; input[i] != '\0'; i++) {
        // Vulnerable: Only filters literal null byte
        if (input[i] != '\0') {
            output[j++] = input[i];
        }
    }
    output[j] = '\0';
    // Doesn't filter %00 or other encoded nulls
}

Fixed Code

# Fixed: Use global replacement and recursive filtering
#!/usr/bin/perl

my $username = GetUntrustedInput();

# Fixed: Use /g for global replacement
# And loop until no more matches
my $prev;
do {
    $prev = $username;
    $username =~ s/\.\.[\\/]//g;  # Handle both / and \
} while ($username ne $prev);

# Better: Validate against allowlist
if ($username !~ /^[a-zA-Z0-9_]+$/) {
    die "Invalid username";
}

my $filename = "/home/user/" . $username;
open(FILE, "<", $filename) or die "Cannot open file";
// Fixed: Use parameterized queries instead of filtering
<?php
function fixed_query($username) {
    $pdo = new PDO($dsn, $user, $password);

    // Fixed: Use prepared statement - no manual escaping needed
    $stmt = $pdo->prepare("SELECT * FROM users WHERE name = ?");
    $stmt->execute([$username]);

    return $stmt->fetchAll();
}

// If filtering is needed, use comprehensive approach
function fixed_escape($input) {
    // Use database-specific escape function
    return pg_escape_string($input);  // PostgreSQL
    // Or: mysqli_real_escape_string($conn, $input);  // MySQL
}
// Fixed: Comprehensive HTML filtering
import org.owasp.encoder.Encode;

public class FixedFilter {
    public String filterXSS(String input) {
        // Fixed: Use proper HTML encoding library
        return Encode.forHtml(input);
    }

    // Alternative: Allowlist approach
    public String filterAllowlist(String input) {
        // Only allow alphanumeric and specific safe characters
        return input.replaceAll("[^a-zA-Z0-9\\s.,!?-]", "");
    }
}
# Fixed: Recursive filtering until stable
import os.path

def fixed_filter_traversal(path):
    # Fixed: Recursively remove until no changes
    while True:
        filtered = path.replace('../', '').replace('..\\', '')
        if filtered == path:
            break
        path = filtered

    return filtered

# Better: Use canonical path comparison
def fixed_validate_path(base_dir, user_path):
    # Resolve to absolute path
    full_path = os.path.realpath(os.path.join(base_dir, user_path))

    # Ensure it's still under base directory
    if not full_path.startswith(os.path.realpath(base_dir) + os.sep):
        raise ValueError("Path traversal detected")

    return full_path
// Fixed: Comprehensive null byte filtering
#include <string.h>
#include <ctype.h>

int fixed_filter_null(const char* input, char* output, size_t output_size) {
    size_t j = 0;
    size_t i = 0;

    while (input[i] != '\0' && j < output_size - 1) {
        // Filter literal null (can't appear in input anyway due to C strings)

        // Filter URL-encoded null %00
        if (input[i] == '%' && input[i+1] == '0' && input[i+2] == '0') {
            i += 3;
            continue;
        }

        // Filter other potentially dangerous sequences
        if (input[i] == '\\' && input[i+1] == '0') {
            i += 2;
            continue;
        }

        output[j++] = input[i++];
    }
    output[j] = '\0';

    return (input[i] == '\0') ? 0 : -1;  // -1 if truncated
}

// Better: Allowlist validation
int validate_input(const char* input) {
    for (int i = 0; input[i] != '\0'; i++) {
        // Only allow alphanumeric and specific punctuation
        if (!isalnum(input[i]) && input[i] != '_' && input[i] != '-') {
            return 0;  // Invalid
        }
    }
    return 1;  // Valid
}

  • CWE-791: Incomplete Filtering of Special Elements (child weakness)
  • CWE-22: Path Traversal (specific exploitation)
  • CWE-89: SQL Injection (specific exploitation)
  • CWE-79: Cross-site Scripting (specific exploitation)

References

  1. MITRE Corporation. "CWE-790: Improper Filtering of Special Elements." https://cwe.mitre.org/data/definitions/790.html
  2. OWASP. "Input Validation Cheat Sheet." https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html
  3. OWASP. "Testing for Input Validation." OWASP Testing Guide.