Insecure deserialization ranks among the most dangerous flaws in the PHP ecosystem: it regularly leads to remote code execution, often without authentication. This article explains what PHP object injection is, why a simple text string can take over a site, and how developers and site administrators alike protect themselves, with real WordPress examples.
Serializing and deserializing: what are we talking about
Serialization turns a PHP variable (array, object) into a text string that can be stored or transmitted. The unserialize() function does the reverse: it rebuilds the original variable. The problem is that rebuilding an object also means instantiating its class and triggering some of its methods. The PHP documentation is explicit: never pass untrusted user input to unserialize(), because rebuilding the data can load and execute code.
An attacker who controls the serialized string can therefore request the creation of objects of any class present in the site's code, with whatever properties they choose. That is the definition of PHP object injection, classified as CWE-502 (deserialization of untrusted data).
What does a serialized string look like? Readable text describing the type and the content. For example, O:4:"User":1:{s:4:"name";s:3:"Bob";} represents an object of class User with a name property set to Bob. All it takes is swapping the class name and properties to target a class that is useful for the attack. That is why a naive filter that merely checks whether the data looks serialized provides no security at all.
Magic methods and the gadget chain
On its own, a forged object does nothing. What makes the attack possible are the magic methods that PHP calls automatically at certain moments:
__wakeup(): called right after the object is rebuilt__destruct(): called when the object is destroyed (at the end of the script, for example)__toString(): called when the object is used as a string
If one of these methods, in a class on the site, performs a sensitive operation (writing a file, calling a function whose name is stored in a property, and so on), the attacker can reach it. By chaining several classes whose methods call one another, they build a gadget chain, or POP chain (Property Oriented Programming), that ends in a dangerous action. No code is injected directly: the attacker only hijacks code that is already there.

A WordPress example: GiveWP (CVE-2024-5932)
In August 2024, Wordfence disclosed a critical flaw in the GiveWP donation plugin, installed on more than 100,000 sites. An unauthenticated attacker could inject a PHP object through the give_title parameter of the donation form. Because a gadget chain existed in the plugin's own code, the injection led to remote code execution and file deletion.
| Item | Value |
|---|---|
| Identifier | CVE-2024-5932 |
| Type | PHP object injection (CWE-502), unauthenticated |
| Affected versions | Up to and including 3.14.1 |
| Patched version | 3.14.2 (August 7, 2024) |
| CVSS score | 10.0 (Wordfence), 9.8 (NVD) |
| Impact | Code execution, file deletion |
The patch did not close the matter: in September 2024, CVE-2024-8353 showed that the initial check could be bypassed because of stripslashes_deep processing applied to the data. Additional hardening was added in version 3.16.2. This is typical of these flaws: fixing the obvious entry point is not always enough, and a second security review is often needed before the issue can be considered closed.
Phar, maybe_unserialize and WordPress core
Two cases shed light on the role of the environment. First, the phar:// wrapper. Before PHP 8.0, merely handling a Phar file (via file_exists, getimagesize, and so on) automatically deserialized its metadata. That is the vector BuddyForms exposed (CVE-2023-26326, CVSS 9.8): an attacker uploaded a disguised Phar file, then had it called through phar://. PHP 8.0 removed this automatic deserialization of Phar metadata, which greatly reduces this risk on modern hosting.
Next, WordPress core itself. In December 2023, version 6.4.2 neutralized a POP chain introduced in the WP_HTML_Token class: its destructor called a function whose name came from a property. WordPress added a __wakeup() method that throws an exception as soon as anyone tries to deserialize this object. The team noted that the flaw was not directly exploitable on its own, but could become serious when combined with certain plugins, especially on multisite. It is a good illustration of a POP chain: core supplied the gadget, and a vulnerable plugin would have supplied the entry point.

Protecting yourself: developers and administrators
For a plugin or theme developer, the rules are clear:
- Never pass user input to
unserialize(); preferjson_decode()andjson_encode()for exchanging data. - If deserialization cannot be avoided, use the
allowed_classesoption (set tofalseto accept no objects at all), available since PHP 7.0 and strictly typed since PHP 7.1. - Validate and sign stored data (for example with
hash_hmac()) to make sure it has not been tampered with. - Be wary of input that reaches WordPress's
maybe_unserialize(), which callsunserialize()as soon as the data looks like serialized content.
For a site administrator who does not touch the code, the defense is more conventional but decisive:
- Update core, plugins and themes without delay; these flaws are almost always fixed in a new release.
- Use a supported PHP version (8.1 or later), which notably rules out automatic deserialization of Phar metadata.
- Reduce the number of installed plugins: less code means fewer potential gadget chains.
- Monitor file integrity and keep tested backups, so you can detect and repair a compromise.
Key takeaways
- PHP object injection abuses unserialize() on attacker-controlled data: it rebuilds objects whose magic methods run on their own.
- A gadget (POP) chain links classes that are already present to reach a dangerous action, without injecting any code.
- Real cases (GiveWP CVE-2024-5932, CVSS 10.0; BuddyForms CVE-2023-26326) have hit widely installed WordPress plugins.
- In code: never pass user input to unserialize(); on the site: updates, supported PHP, fewer plugins, integrity monitoring.
Where WP Masquerade fits in
WP Masquerade does not fix a plugin flaw, nor does it filter a deserialization payload: it is not a web application firewall, and its guide says so clearly. Its contribution is complementary. Hiding public signatures and hardening make the profiling that precedes the targeting of a specific plugin harder. Above all, after a successful attack, the core integrity check (Pro) flags modified files, and email alerts warn you quickly. An upcoming Pro feature adds alerts on vulnerable plugins, with details of the flaw, so you can update as early as possible. The fundamental defense against object injection remains prompt updates and code that never deserializes user input.
Videos to go further
Sources
- NVD - CVE-2024-5932 (GiveWP) (opens in a new tab)
- NVD - CVE-2023-26326 (BuddyForms, phar) (opens in a new tab)
- php.net - Manual: unserialize() and allowed_classes (opens in a new tab)
- WordPress.org - Version 6.4.2 (maintenance and security) (opens in a new tab)
Other sources consulted: further CVE records, official documentation and Wordfence database.


