← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

Insecure Deserialization

security CWE-502 OWASP A8:2021 Advanced

Also Known As

PHP object injection unserialize exploit gadget chain PHP deserialization RCE

TL;DR

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.

Explanation

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.

Watch Out

Even unserialize($data, ['allowed_classes' => false]) can be dangerous if your code then re-constructs objects from the resulting array — validate and whitelist the structure of the decoded data.

Common 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.

Code Examples

💡 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.
✗ Vulnerable
// Cookie contains serialized object — attacker controlled:
$prefs = unserialize(base64_decode($_COOKIE['prefs']));
// If codebase has gadget classes, this is RCE
✓ Fixed
// Use JSON instead:
$prefs = json_decode(base64_decode($_COOKIE['prefs']), true);
if (!is_array($prefs)) {
    $prefs = [];
}
// Or if you must deserialize, whitelist no classes:
$data = unserialize($input, ['allowed_classes' => false]);

Added 10 Apr 2026
Views 15
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings W 0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 1 ping F 0 pings S 1 ping S 1 ping M 0 pings T 0 pings W 0 pings T 1 ping F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W 1 ping T 0 pings F 0 pings S 1 ping S 1 ping M 0 pings T 0 pings W 0 pings T
No pings yet today
No pings yesterday
Perplexity 3 SEMrush 3 Google 2 ChatGPT 1 Unknown AI 1 Ahrefs 1 Qwen 1
crawler 11 crawler_json 1
DEV INTEL Tools & Severity
🔴 Critical ⚙ Fix effort: Medium
⚡ Quick Fix
Replace unserialize($data) with json_decode($data, true); if deserialization is required, use unserialize($data, ['allowed_classes' => false])
🔗 Prerequisites
🔍 Detection Hints
unserialize( with $_COOKIE, $_GET, $_POST, $_REQUEST, or any external input as argument
Auto-detectable: ✓ Yes semgrep psalm phpstan
⚠ Related Problems
🤖 AI Agent
Confidence: High False Positives: Low ✗ Manual fix Fix: Medium Context: Function Tests: Update
CWE-502 CWE-94 CWE-915

✓ schema.org compliant