{
    "slug": "phar_injection",
    "term": "PHAR Deserialization Attack",
    "category": "security",
    "difficulty": "advanced",
    "short": "PHP's phar:// stream wrapper triggers deserialization of PHAR metadata on any file operation, enabling PHP object injection without unserialize().",
    "long": "PHAR (PHP Archive) files embed serialized PHP metadata in their stub. Any PHP file function (file_exists(), fopen(), copy(), rename(), include()) that operates on a phar:// URI will deserialize this metadata — triggering magic methods and enabling PHP Object Injection without a call to unserialize(). An attacker who can upload a file (even one with a safe extension like .jpg) and control a path passed to a file function can exploit this. Mitigations: disable the phar stream wrapper (Phar::unlinkArchive, stream_wrapper_unregister('phar')), validate file paths strictly, and use realpath() before file operations.",
    "aliases": [
        "PHAR deserialization",
        "PHP archive injection",
        "phar:// attack"
    ],
    "tags": [
        "php",
        "deserialization",
        "rce",
        "injection"
    ],
    "misconception": "PHAR injection requires the attacker to upload a .phar file. Any file operation using a user-controlled path — file_exists(), fopen(), copy() — can trigger PHAR deserialization if the path starts with phar://, even on an uploaded image.",
    "why_it_matters": "PHP archive files are deserialized when accessed via any stream wrapper that triggers PHP's file functions — an attacker who can upload a PHAR file and trigger a file function on it gets deserialization RCE.",
    "common_mistakes": [
        "Allowing user file uploads to be passed to file_exists(), file_get_contents(), or similar — a phar:// URL triggers deserialization.",
        "Not disabling PHAR-based stream wrappers when user input is used in file paths.",
        "Mime-type checking uploads but not considering that .jpg files can be valid PHAR archives.",
        "Not restricting allowed PHP stream wrappers via allow_url_fopen and htaccess rules."
    ],
    "when_to_use": [],
    "avoid_when": [],
    "related": [
        "php_object_injection",
        "arbitrary_file_upload",
        "insecure_deserialization",
        "path_traversal"
    ],
    "prerequisites": [
        "arbitrary_file_upload",
        "php_object_injection",
        "insecure_deserialization"
    ],
    "refs": [
        "https://owasp.org/www-community/vulnerabilities/PHP_Object_Injection",
        "https://i.blackhat.com/us-18/Thu-August-9/us-18-Thomas-It's-A-PHP-Unserialization-Vulnerability-Jim-But-Not-As-We-Know-It-wp.pdf"
    ],
    "bad_code": "// User-controlled path triggers PHAR deserialization:\n$file = $_GET['file'];\nif (file_exists($file)) { // Attacker: ?file=phar://uploads/evil.jpg\n    echo file_get_contents($file);\n}",
    "good_code": "// Validate file paths — never pass user input to file functions:\nfunction safeRead(string $userPath): string {\n    // Realpath resolves .. and symlinks:\n    $base = realpath('/var/www/uploads/');\n    $full = realpath($base . '/' . basename($userPath));\n\n    // Ensure resolved path is inside the allowed directory:\n    if (!$full || !str_starts_with($full, $base . '/')) {\n        throw new SecurityException('Path traversal attempt');\n    }\n\n    return file_get_contents($full);\n}\n\n// Disable phar stream wrapper if not needed:\nstream_wrapper_unregister('phar');\n\n// Validate file magic bytes, not extension:\n$finfo = new \\finfo(FILEINFO_MIME_TYPE);\n$type  = $finfo->file($path); // Check actual content type",
    "quick_fix": "Never pass user-controlled paths to file functions (file_exists, include, fopen) — validate and canonicalise all paths with realpath() first",
    "severity": "critical",
    "effort": "medium",
    "created": "2026-03-15",
    "updated": "2026-03-22",
    "citation": {
        "canonical_url": "https://codeclaritylab.com/glossary/phar_injection",
        "html_url": "https://codeclaritylab.com/glossary/phar_injection",
        "json_url": "https://codeclaritylab.com/glossary/phar_injection.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": "[PHAR Deserialization Attack](https://codeclaritylab.com/glossary/phar_injection) (CodeClarityLab)",
                "footer_credit": "Source: CodeClarityLab Glossary — https://codeclaritylab.com/glossary/phar_injection"
            }
        }
    }
}