← Home ← Codex ← DEBT ← Engine
Browse by Category
+ added · updated 7d
← Back to glossary

Deserialization Gadget Chains

Security PHP 5.0+ Advanced
debt(d5/e5/b5/t7)
d5 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'specialist tool catches it' (d5). The detection_hints list semgrep, psalm, and phpggc as tools that can identify unserialize() calls on user-controlled input. These are specialist static analysis tools, not default linters — requires deliberate tooling setup to catch.

e5 Effort Remediation debt — work required to fix once spotted

Closest to 'touches multiple files / significant refactor' (e5). The quick_fix says 'Replace unserialize() with json_decode() everywhere' — while each individual fix is a simple replacement, serialized data formats are often embedded in session handling, caching layers, queue systems, and database storage, requiring coordinated changes across multiple components and potentially data migration.

b5 Burden Structural debt — long-term weight of choosing wrong

Closest to 'persistent productivity tax' (b5). Applies to both web and cli contexts across PHP 5.0+. Once unserialize() patterns are established in session handling, caching, or inter-service communication, every new feature touching those systems must maintain awareness of the serialization format. Not architectural-level burden, but a consistent tax on data handling throughout the codebase.

t7 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'serious trap' (t7). The misconception field explicitly states that developers believe 'Object injection is only dangerous if the codebase has obviously dangerous code' — this contradicts reality because gadget chains exploit legitimate framework classes (Guzzle, Monolog, Laravel) with dangerous magic methods. Developers familiar with injection attacks elsewhere expect to see the danger in their own code, not in trusted dependencies.

About DEBT scoring →

Also Known As

PHP gadget chain PHPGGC object injection RCE deserialization RCE

TL;DR

PHP object injection exploits that chain existing class methods (__wakeup, __destruct, __toString) to achieve remote code execution when unserialize() processes attacker-controlled data.

Explanation

A gadget chain strings together existing PHP class methods invoked during deserialisation. When unserialize() processes an object, PHP calls magic methods: __wakeup (on deserialisation), __destruct (on garbage collection), __toString (if cast to string), __get/__set (property access). If the codebase contains classes with dangerous operations in these methods (file writes, eval, shell commands), an attacker crafts a serialised payload that instantiates those classes with controlled properties, chaining the magic methods into RCE. Tools: PHPGGC (PHP Generic Gadget Chains) generates payloads for popular frameworks.

Common Misconception

Object injection is only dangerous if the codebase has obviously dangerous code — gadget chains use legitimate framework classes (Guzzle, Monolog, Laravel) that have dangerous magic method implementations when given attacker-controlled properties.

Why It Matters

Deserialization vulnerabilities in PHP applications using popular frameworks are frequently exploitable to RCE — PHPGGC has pre-built chains for Laravel, Symfony, Guzzle, and many others.

Common Mistakes

  • unserialize() on any user-controlled data — use JSON instead.
  • Thinking allowed_classes: false is sufficient — it prevents object instantiation but some PHP versions have bypass techniques.
  • Not patching deserialization vulnerabilities in dependencies — many CVEs in Composer packages.
  • Using serialize() to store session data in user-accessible locations.

Code Examples

✗ Vulnerable
// Direct unserialize of user input — critical RCE vulnerability:
$data = unserialize(base64_decode($_COOKIE['session_data']));
// Attacker sends PHPGGC payload for Laravel gadget chain
// __destruct chain → file_put_contents → webshell written
// → full server compromise
✓ Fixed
// Never unserialize user input — use JSON:
$data = json_decode(base64_decode($_COOKIE['session_data']), true);
if (!is_array($data)) throw new InvalidSessionException();

// If unserialize is unavoidable (legacy data):
$data = unserialize($serialized, ['allowed_classes' => false]);
// false = no objects instantiated, only scalar types
// HMAC-sign the serialized data to detect tampering:
$payload = $data . '|' . hash_hmac('sha256', $data, SECRET_KEY);
// Verify before deserializing:
[$data, $mac] = explode('|', $payload, 2);
if (!hash_equals(hash_hmac('sha256', $data, SECRET_KEY), $mac)) die('Tampered');

Added 16 Mar 2026
Edited 22 Mar 2026
Views 104
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
2 pings F 0 pings S 0 pings S 0 pings M 0 pings T 1 ping W 1 ping T 0 pings F 0 pings S 0 pings S 2 pings M 1 ping T 0 pings W 0 pings T 0 pings F 2 pings S 0 pings S 0 pings M 0 pings T 1 ping W 0 pings T 0 pings F 2 pings S 0 pings S 1 ping M 0 pings T 1 ping W 0 pings T 0 pings F 2 pings S
PetalBot 1 Amazonbot 1
No pings yesterday
PetalBot 13 Amazonbot 11 Ahrefs 7 ChatGPT 7 SEMrush 5 Scrapy 4 Bing 3 Sogou 3 Perplexity 2 Google 2 Brave Search 2 Applebot 2 Majestic 1 Meta AI 1 Twitter/X 1 Unknown AI 1
crawler 60 crawler_json 5
DEV INTEL Tools & Severity
🔴 Critical ⚙ Fix effort: High
⚡ Quick Fix
Replace unserialize() with json_decode() everywhere — there is no safe way to unserialize untrusted input in PHP because gadget chains exist in popular frameworks
📦 Applies To
PHP 5.0+ web cli
🔗 Prerequisites
🔍 Detection Hints
unserialize() of any user-controlled input including cookies, GET/POST params, database values from untrusted sources
Auto-detectable: ✓ Yes semgrep psalm phpgcc
⚠ Related Problems
🤖 AI Agent
Confidence: High False Positives: Low ✗ Manual fix Fix: High Context: File Tests: Update
CWE-502


✓ schema.org compliant