{
    "slug": "deserialization",
    "term": "Insecure Deserialization",
    "category": "security",
    "difficulty": "advanced",
    "short": "Deserializing attacker-controlled data can trigger arbitrary object construction and method calls — PHP's unserialize() with untrusted input enables remote code execution via gadget chains in the loaded class graph.",
    "long": "PHP's unserialize() reconstructs PHP objects from a byte string, calling __wakeup() and __destruct() magic methods on every instantiated object. If the codebase contains classes whose __destruct() or __wakeup() methods perform dangerous operations (file deletion, eval, system calls) — called gadget classes — an attacker can craft a serialized string that instantiates those classes with attacker-controlled properties, achieving remote code execution or file system manipulation without ever exploiting a separate vulnerability. This technique is called a gadget chain. Popular PHP frameworks (Laravel, Symfony, Yii) and libraries (Monolog, Guzzle) have had known gadget chains. Mitigations: never deserialize untrusted data with unserialize(); use JSON (json_decode) or a safe structured format instead; if deserialization is unavoidable, pass allowed_classes as the second argument to whitelist which classes may be instantiated. The PHPGGC tool generates ready-made gadget chain payloads for audit and testing.",
    "aliases": [
        "PHP object injection",
        "unserialize exploit",
        "gadget chain",
        "PHP deserialization RCE"
    ],
    "tags": [
        "security",
        "php",
        "rce",
        "owasp",
        "deserialization",
        "object-injection"
    ],
    "misconception": "Signing or encoding the serialized data (base64, HMAC) does not prevent the attack if the attacker can still inject into the serialized byte string before verification — always verify the signature before deserializing, never after.",
    "why_it_matters": "Insecure deserialization is OWASP A8 and has led to critical RCE vulnerabilities in major PHP applications — any use of unserialize() on user-supplied or cookie data is a high-severity finding.",
    "common_mistakes": [
        "Storing serialized PHP objects in cookies or URL parameters — these are trivially modified by the client.",
        "Using unserialize() without the allowed_classes option — all loaded classes become potential gadgets.",
        "Verifying the HMAC signature after deserializing — the dangerous object construction happens during unserialize(), before your code can check the signature.",
        "Assuming private data (database, Redis) is safe — supply-chain attacks or SSRF can inject into internal stores."
    ],
    "when_to_use": [],
    "avoid_when": [],
    "related": [
        "php_object_injection",
        "magic_methods",
        "rce",
        "insecure_deserialization",
        "serialize_function"
    ],
    "prerequisites": [
        "php_object_injection",
        "magic_methods",
        "input_validation"
    ],
    "refs": [
        "https://owasp.org/www-community/vulnerabilities/PHP_Object_Injection",
        "https://github.com/ambionics/phpggc"
    ],
    "bad_code": "// Cookie contains serialized object — attacker controlled:\n$prefs = unserialize(base64_decode($_COOKIE['prefs']));\n// If codebase has gadget classes, this is RCE",
    "good_code": "// Use JSON instead:\n$prefs = json_decode(base64_decode($_COOKIE['prefs']), true);\nif (!is_array($prefs)) {\n    $prefs = [];\n}\n// Or if you must deserialize, whitelist no classes:\n$data = unserialize($input, ['allowed_classes' => false]);",
    "example_note": "The bad example deserializes a client-controlled cookie — any gadget class in the autoloaded codebase can be weaponised. Switching to JSON eliminates object instantiation entirely; allowed_classes=>false is a safer fallback when JSON is not an option.",
    "quick_fix": "Replace unserialize($data) with json_decode($data, true); if deserialization is required, use unserialize($data, ['allowed_classes' => false])",
    "severity": "critical",
    "effort": "medium",
    "created": "2026-04-10",
    "updated": "2026-04-10",
    "citation": {
        "canonical_url": "https://codeclaritylab.com/glossary/deserialization",
        "html_url": "https://codeclaritylab.com/glossary/deserialization",
        "json_url": "https://codeclaritylab.com/glossary/deserialization.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": "[Insecure Deserialization](https://codeclaritylab.com/glossary/deserialization) (CodeClarityLab)",
                "footer_credit": "Source: CodeClarityLab Glossary — https://codeclaritylab.com/glossary/deserialization"
            }
        }
    }
}