
A security vulnerability that has been hiding inside PHP since 2005 — quietly surviving two decades of audits, engine rewrites, and dozens of related CVEs — has finally been found, and it took an AI to catch it. Yeah, another flaw discovered by AI after the critical Linux Copy Fail flaw, which leads to root access on almost every major Linux distro.
Researchers at Calif published a detailed write-up today revealing a use-after-free (UAF) bug in PHP's unserialize() function, a code path that has been exploitable since PHP 5.1 shipped the Serializable interface twenty-one years ago.
The flaw allows an attacker to achieve remote code execution (RCE) against the latest PHP release, 8.5.5, in roughly 2,000 HTTP requests — with no hardcoded memory offsets and no access to /proc.
The root cause is a two-line omission. PHP uses an internal lock, BG(serialize_lock), to keep each unserialize() call's reference table private. Every user-code dispatch point inside the deserializer — __wakeup, __unserialize, __destruct — increments that lock before running PHP code. One dispatch site, zend_user_unserialize(), the handler for the Serializable interface, never did. The missing increment means a nested unserialize() call inside a class's own unserialize() method silently shares the outer call's memory table.
An attacker who can trigger a property-table resize during that window gets a dangling pointer, which leads to memory corruption and, ultimately, arbitrary code execution.
The bug survived the PHP 7 engine rewrite in 2016 untouched. It also outlived a 2017 decision by the PHP project to stop treating unserialize() memory bugs as security vulnerabilities — a policy that has aged poorly.
How AI Found What Humans Missed
Calif built an audit tool, /php-unserialize-audit, by feeding roughly twenty historical unserialize advisories into Claude and distilling them into a structured bug taxonomy. That tool rediscovered all twelve known phpcodz advisories when run against PHP 5.6.40, then flagged the Serializable reentrancy issue as novel when pointed at 8.5.5.
The pattern echoes what we reported earlier this year when AI-assisted analysis exposed CopyFail, the critical Linux kernel memory corruption vulnerability. In both cases, AI didn't replace researchers — it handled the exhausting pattern-matching work that lets experts focus on what the findings actually mean.
The remote exploit carries a significant precondition: the target application must load a class implementing Serializable that calls unserialize() recursively on user-supplied data and then mutates the resulting object's properties. That combination is uncommon in production code. The local exploit, however, carries no such restriction — any PHP process that passes attacker-controlled input to unserialize() is vulnerable, and the researchers confirmed it bypasses disable_functions entirely.
The researchers have open-sourced both the exploit and the audit skill.
What to Do
- Audit any code that passes user input to
unserialize()— PHP's own documentation has warned against this for years. - Replace
unserialize()withjson_decode()wherever possible for untrusted data. - Monitor for PHP patches addressing this Serializable dispatch path.
- Treat
disable_functionsas a speed bump, not a security boundary.
PHP's unserialize() has been a vulnerability factory since 2007. This bug suggests it still has more to give — and that AI-assisted auditing is quickly becoming the tool that will drain it.