---
title: "PHP deserialization and object injection explained"
description: "PHP object injection explained: how unserialize() and POP chains lead to code execution, with real WordPress cases and the defenses that work. Read on."
language: "en"
locale: "en-US"
type: "article"
canonical: "https://www.wp-masquerade.com/php-deserialization-object-injection/"
published: "2026-09-29T07:00:00+00:00"
modified: "2026-10-28T22:59:23+00:00"
translations:
  en-US: "https://www.wp-masquerade.com/php-deserialization-object-injection/index.md"
  fr-FR: "https://www.wp-masquerade.com/fr/deserialisation-php-object-injection/index.md"
  es-ES: "https://www.wp-masquerade.com/es/deserializacion-php-inyeccion-objetos/index.md"
  de-DE: "https://www.wp-masquerade.com/de/php-deserialisierung-object-injection/index.md"
  it-IT: "https://www.wp-masquerade.com/it/deserializzazione-php-iniezione-oggetti/index.md"
  pt-BR: "https://www.wp-masquerade.com/pt/desserializacao-php-injecao-objetos/index.md"
  nl-NL: "https://www.wp-masquerade.com/nl/php-deserialisatie-objectinjectie/index.md"
---

# PHP deserialization and object injection explained

How a simple text string passed to unserialize() can take over a PHP site: magic methods, gadget chains, real WordPress cases and protections.

Insecure deserialization ranks among the most dangerous flaws in the PHP ecosystem: it regularly leads to [remote code execution](https://www.wp-masquerade.com/glossary/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.

![Diagram: attacker-controlled data, unserialize, magic methods and a POP chain leading to a dangerous action](https://www.wp-masquerade.com/media/2026/10/mecanisme-en.webp)

*The principle: forged data wakes up methods that chain together until the final action.*

## 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 |

*CVE-2024-5932: an object injection given the maximum score by Wordfence.*

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](https://www.wp-masquerade.com/glossary/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.

![Timeline of PHP object injection cases in the WordPress ecosystem from 2023 to 2025](https://www.wp-masquerade.com/media/2026/10/cas-en.webp)

*Deserialization remains a recurring source of critical flaws, in core and plugins alike.*

## Protecting yourself: developers and administrators

For a plugin or theme developer, the rules are clear:

- Never pass user input to `unserialize()`; prefer `json_decode()` and `json_encode()` for exchanging data.
- If deserialization cannot be avoided, use the `allowed_classes` option (set to `false` to 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 calls `unserialize()` 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](https://www.wp-masquerade.com/glossary/waf/), and its guide says so clearly. Its contribution is complementary. Hiding public signatures and [hardening](https://www.wp-masquerade.com/features/hardening/) make the profiling that precedes the targeting of a specific plugin harder. Above all, after a successful attack, the [core integrity check](https://www.wp-masquerade.com/features/wordpress-integrity-check/) (Pro) flags modified files, and [email alerts](https://www.wp-masquerade.com/features/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

*A visual explanation of how insecure deserialization works.*

*A hands-on introduction to PHP object injection and gadget chains.*

## Sources

- [NVD - CVE-2024-5932 (GiveWP)](https://nvd.nist.gov/vuln/detail/CVE-2024-5932)
- [NVD - CVE-2023-26326 (BuddyForms, phar)](https://nvd.nist.gov/vuln/detail/CVE-2023-26326)
- [php.net - Manual: unserialize() and allowed_classes](https://www.php.net/manual/fr/function.unserialize.php)
- [WordPress.org - Version 6.4.2 (maintenance and security)](https://wordpress.org/news/2023/12/wordpress-6-4-2-maintenance-security-release/)

Other sources consulted: further CVE records, official documentation and Wordfence database.

## WordPress security, without the noise

One e-mail when something matters: new attacks seen in the wild, plugin updates and practical guides. No spam, unsubscribe in one click.
