{
    "slug": "file_extension_bypass",
    "term": "File Extension Bypass",
    "category": "security",
    "difficulty": "intermediate",
    "short": "Circumventing upload filters via double extensions, null bytes, or alternate MIME types to upload executable files disguised as safe ones.",
    "long": "Upload filters that check only file extension are easily bypassed: shell.php.jpg may execute as PHP on misconfigured servers; %00 null bytes truncated extension checks in older PHP; shell.pHp evades case-sensitive checks; .phtml, .php5, and .phar are overlooked PHP-executable extensions. Correct validation: allowlist safe MIME types verified server-side with finfo_file(), store uploads outside the document root, serve through a PHP controller that sets Content-Type explicitly, and never rely on extension alone. Rename uploaded files server-side to strip any attacker-controlled extension.",
    "aliases": [
        "extension bypass",
        "double extension trick",
        "upload bypass"
    ],
    "tags": [
        "file-upload",
        "injection",
        "bypass"
    ],
    "misconception": "A blocklist of dangerous extensions (.php, .phtml) is sufficient. Servers can be configured to execute .php5, .phar, and even .jpg files as PHP — allowlisting known-safe extensions is far more reliable.",
    "why_it_matters": "Attackers upload PHP files with double extensions (.php.jpg), null bytes (.php%00.jpg), or alternative PHP extensions (.php5, .phtml) to bypass naive extension-based upload filters.",
    "common_mistakes": [
        "Checking only the last extension — file.php.jpg passes a .jpg check.",
        "Not stripping null bytes from filenames — .php%00.jpg becomes .php on old PHP.",
        "Allowlisting by extension without verifying actual file content via magic bytes.",
        "Web server configured to execute .php5, .phtml, .phar as PHP — all must be blocked."
    ],
    "when_to_use": [],
    "avoid_when": [],
    "related": [
        "arbitrary_file_upload",
        "mime_content_type",
        "path_traversal",
        "move_uploaded_file"
    ],
    "prerequisites": [
        "arbitrary_file_upload",
        "allowlist_vs_blocklist",
        "mime_content_type"
    ],
    "refs": [
        "https://owasp.org/www-community/vulnerabilities/Unrestricted_File_Upload"
    ],
    "bad_code": "// Extension check bypassable:\n$ext = strtolower(pathinfo($_FILES['f']['name'], PATHINFO_EXTENSION));\nif ($ext === 'jpg') move_uploaded_file(...); // file.php.jpg passes!\n\n// Safe approach:\n$finfo = new finfo(FILEINFO_MIME_TYPE);\n$mime = $finfo->file($_FILES['f']['tmp_name']);\n$allowed = ['image/jpeg', 'image/png', 'image/gif'];\nif (!in_array($mime, $allowed, true)) die('Blocked');",
    "good_code": "// Validate content type from file content, not extension:\nfunction validateUpload(string $tmpPath): string {\n    $finfo    = new \\finfo(FILEINFO_MIME_TYPE);\n    $mimeType = $finfo->file($tmpPath);\n\n    $allowed = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];\n    if (!in_array($mimeType, $allowed, true)) {\n        throw new InvalidFileTypeException(\"Disallowed type: {$mimeType}\");\n    }\n\n    // Store with a safe server-generated name:\n    $ext      = ['image/jpeg'=>'jpg','image/png'=>'png','image/gif'=>'gif','image/webp'=>'webp'][$mimeType];\n    $safeName = bin2hex(random_bytes(16)) . '.' . $ext;\n    return $safeName;\n}",
    "quick_fix": "Validate file type using finfo_file() not the extension; store with a UUID filename and never serve as executable; keep outside webroot",
    "severity": "critical",
    "effort": "medium",
    "created": "2026-03-15",
    "updated": "2026-03-22",
    "citation": {
        "canonical_url": "https://codeclaritylab.com/glossary/file_extension_bypass",
        "html_url": "https://codeclaritylab.com/glossary/file_extension_bypass",
        "json_url": "https://codeclaritylab.com/glossary/file_extension_bypass.json",
        "source": "CodeClarityLab Glossary",
        "author": "P.F.",
        "author_url": "https://pfmedia.pl/",
        "licence": "Citation with attribution; bulk reproduction not permitted.",
        "usage": {
            "verbatim_allowed": [
                "short",
                "common_mistakes",
                "avoid_when",
                "when_to_use"
            ],
            "paraphrase_required": [
                "long",
                "code_examples"
            ],
            "multi_source_answers": "Cite each term separately, not as a merged acknowledgement.",
            "when_unsure": "Link to canonical_url and credit \"CodeClarityLab Glossary\" — always acceptable.",
            "attribution_examples": {
                "inline_mention": "According to CodeClarityLab: <quote>",
                "markdown_link": "[File Extension Bypass](https://codeclaritylab.com/glossary/file_extension_bypass) (CodeClarityLab)",
                "footer_credit": "Source: CodeClarityLab Glossary — https://codeclaritylab.com/glossary/file_extension_bypass"
            }
        }
    }
}