CVE-2026-7654: PHP Object Injection Leading to RCE in Admin Columns WordPress Plugin
A PHP Object Injection vulnerability tracked as CVE-2026-7654 has been disclosed in the Admin Columns plugin for WordPress, affecting all versions up to and including 7.0.18. The flaw allows an attacker with at least subscriber-level access to inject a crafted PHP object via an unsafe unserialize() call, potentially leading to Remote Code Execution (RCE) on the underlying server.
The vulnerability carries a CVSS v3.1 score of 8.8 (High) and is classified under CWE-502 — Deserialization of Untrusted Data.
Vulnerability Overview
| Attribute | Value |
|---|---|
| CVE ID | CVE-2026-7654 |
| CVSS Score | 8.8 (High) |
| CWE Classification | CWE-502 — Deserialization of Untrusted Data |
| Affected Plugin | Admin Columns for WordPress |
| Affected Versions | ≤ 7.0.18 |
| Vulnerable Function | IdsToCollection::get_ids_from_string() |
| Root Cause | unserialize() called without allowed_classes restriction |
| Attack Vector | Network (Remote) |
| Authentication Required | Low (subscriber-level) |
| Patch Available | Pending — update to version above 7.0.18 |
Technical Details
Affected Component
The vulnerability exists within the IdsToCollection::get_ids_from_string() function inside the Admin Columns plugin. This function is responsible for converting serialized column ID data — supplied via user input — back into PHP objects using the native unserialize() function.
Root Cause
The core problem is the absence of the allowed_classes parameter in the unserialize() call:
// Vulnerable pattern — no class restriction
$ids = unserialize($user_input);
// Secure pattern — restricts deserialization to expected classes only
$ids = unserialize($user_input, ['allowed_classes' => false]);
// or restrict to specific classes:
$ids = unserialize($user_input, ['allowed_classes' => ['ExpectedClassName']]);Without the allowed_classes restriction, PHP will instantiate any class that exists in the application's codebase when deserializing the supplied data. If a suitable Property-Oriented Programming (POP) chain is available in the application or any loaded dependency, an attacker can trigger arbitrary method calls during deserialization.
Exploitation Path
Exploiting PHP Object Injection typically follows this pattern:
1. Attacker identifies a class in the codebase (or a loaded library) with
a magic method (__destruct, __wakeup, __toString) that performs a
dangerous operation (file write, command execution, etc.)
2. Attacker crafts a serialized PHP object string that instantiates this
class with attacker-controlled property values
3. Attacker submits the serialized payload via the vulnerable Admin Columns
input field
4. When IdsToCollection::get_ids_from_string() calls unserialize() on the
payload, PHP instantiates the gadget class
5. The magic method fires automatically, executing the attacker's code
in the context of the web server process
The presence of widely-used libraries (such as Symfony, Guzzle, Monolog, or other WordPress plugins with compatible gadget chains) significantly increases the likelihood of a viable RCE chain.
Attack Surface and Risk Factors
Who Can Exploit This?
The vulnerability requires at least subscriber-level authentication — meaning a registered WordPress user with minimal privileges. This is a critical distinction: on WordPress sites that allow public registration (e-commerce platforms, membership sites, forums), any visitor can register an account and trigger the vulnerability.
Severity Amplifiers
Several factors increase the real-world risk:
- WordPress ecosystem complexity — Large WordPress installations typically load dozens of plugins and themes, each potentially contributing gadget classes to the serialization namespace
- Shared hosting — RCE on shared hosting infrastructure can have blast radius beyond the targeted site
- Admin Columns popularity — Admin Columns is a widely deployed plugin used to customize WordPress admin list tables, giving this vulnerability significant exposure
- Low authentication bar — Subscriber-level access is trivially obtained on most WordPress sites
Remediation
Immediate Actions
- Update Admin Columns to the patched release above version 7.0.18 as soon as it is available
- Disable user registration if not required by the site's functionality (
Settings > General > Anyone can register) - Audit existing subscriber accounts for suspicious activity
- Deploy a WAF with PHP deserialization detection rules as a temporary compensating control
Patching the Root Cause
The upstream fix should restrict deserialization to expected class types:
// Safe approach — disallow all class instantiation
$ids = unserialize($raw_ids, ['allowed_classes' => false]);
// If specific classes are needed:
$ids = unserialize($raw_ids, ['allowed_classes' => [IdsCollection::class]]);Detection
Review PHP error logs and web server access logs for serialization-related patterns:
# Check for PHP serialization patterns in access logs
grep -E "O:[0-9]+:" /var/log/apache2/access.log
# Check PHP error log for deserialization warnings
grep -i "unserialize" /var/log/php_errors.logPHP Object Injection Background
PHP Object Injection (POI) is a class of vulnerabilities that arise when user-supplied data is passed to PHP's unserialize() function without validation. When PHP deserializes an object, it automatically invokes several magic methods — notably __wakeup() and __destruct() — on the newly instantiated object.
If the codebase (or any loaded library) contains a class whose magic methods perform dangerous operations using object properties (such as writing files, executing system commands, or making network requests), an attacker can craft a serialized object that triggers these operations with arbitrary parameters.
This attack pattern is well-documented and has a history of high-profile exploits in major PHP applications including Magento, Joomla, and numerous WordPress plugins.
Impact Assessment
| Impact Area | Description |
|---|---|
| Remote Code Execution | High — viable if a POP chain exists in the loaded codebase |
| Data Theft | High — full database access and file system read possible via RCE |
| Site Defacement | High — file write capabilities enable template modification |
| Privilege Escalation | High — RCE as web server user; potential for full server compromise on misconfigured systems |
| Lateral Movement | Medium — depends on server and network configuration |
Key Takeaways
- CVE-2026-7654 is a CVSS 8.8 PHP Object Injection flaw in Admin Columns for WordPress (≤ 7.0.18), exploitable by any authenticated subscriber-level user
- The vulnerability stems from calling
unserialize()without anallowed_classesrestriction inIdsToCollection::get_ids_from_string() - Successful exploitation depends on the availability of a PHP POP chain in the application — common in large WordPress deployments with many plugins
- Update Admin Columns immediately upon patch release; disable public registration as a temporary mitigation
- WordPress site operators should audit all plugins for unsafe
unserialize()usage as a broader hardening measure