CVE-2026-115806: Prime Mover PHP Object Injection Leads to Privilege Escalation - Safe Security

CVE-2026-115806: Prime Mover PHP Object Injection Leads to Privilege Escalation

Oct 29, 2026 9 minute read

1. Introduction

CVE-2026-115806 is a PHP object-injection flaw in Prime Mover – Backup and Migration for WordPress. An unauthenticated visitor can store a base64-encoded serialized object in a public comment. The value is processed later when an administrator runs the plugin’s migration search-and-replace routine.

In a controlled lab, the vulnerable release changed WordPress role and registration options. A newly registered account retained the Subscriber role label but gained the tested manage_options capability and could open General Settings. This is a stored, administrator-triggered privilege-escalation path; the reproduction did not demonstrate direct code execution.

2. Prime Mover Description

Prime Mover exports and restores WordPress site data and files. During a restore, its importer can search and replace site-specific values in database content. The plugin bundles the Freemius SDK, which supplies the gadget methods used in the object-injection chain.

3. Vulnerability Severity

Field Value
CVE CVE-2026-115806; CWE-502, deserialization of untrusted data
Severity Critical; CVSS 3.1: 9.8; AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Affected Prime Mover versions up to and including 2.2.1
Fixed Prime Mover 2.2.2; the official changelog records the object-injection hardening
Lab comparison 2.2.1 and 2.2.2, on WordPress 7.1 (patch level not recorded), PHP 8.3.36, and MariaDB 11.8.9

The published CVSS vector assigns UI:N. The reproduced workflow nevertheless requires an administrator to run a restore before the stored comment is processed. This article reports the published score without recalculating it and describes the restore as an operational condition.

Wordfence published its advisory on 22 October 2026; the CVE record was published on 24 October. See the Wordfence advisory and the CVE record for the reported scope and score. Wordfence identifies Civitasmass as the researcher, and Prime Mover’s 2.2.2 changelog credits Civitasmass/Wordfence for the security hardening.

4. Scope of Impact

The advisory identifies all versions through 2.2.1 as affected. The 2.2.2 changelog lists separate entries for the unserialize hardening and a Freemius SDK update. Wordfence’s advisory still displayed ‘No known patch available’ when checked on 26 October 2026, although the official changelog and our package comparison identify 2.2.2 as the fixed release. Our differential testing directly compared 2.2.1 with 2.2.2; it did not separately test every earlier plugin version. The reproduced path depends on the conditions below.

Condition What it means
Vulnerable plugin Prime Mover 2.2.1 or earlier is active.
Public comment path At least one public post accepts comments. The payload is stored as comment content; moderation did not prevent later processing in the lab.
Restore trigger An administrator runs a Prime Mover restore/import that reaches the importer’s search-and-replace stage.
Matching search value The decoded content must contain a migration search string. The same-site lab used the site URL; a cross-domain restore would require a matching value from the source migration.
Impact target The demonstrated payload updated wp_user_roles; the extended payload also enabled users_can_register.

5. Where is the vulnerability present?

The flaw occurs in the interaction between the public comment database and Prime Mover’s importer. WordPress accepts a base64-encoded serialized object as comment content. The payload is not deserialized when the comment is submitted; it remains stored until the importer scans comment rows during a restore.

In Prime Mover 2.2.1, recursiveUnserializeReplace() in the search-and-replace routine calls unserialize() without an allowed_classes restriction after the content passes the base64, serialized-data, and migration-search-string checks. The reviewed import path reaches this routine through PrimeMoverSearchReplace::load(). The advisory also describes export or restore as trigger contexts; our reproduction exercised the importer/restore path.

A property-walk step turns the deserialized data into a magic-method call. The routine trims string property names before assigning them back to the object. A dynamic property serialized with surrounding spaces is therefore assigned under a different name. In the crafted object, that assignment invokes FS_Clone_Manager::__set().

The bundled Freemius gadget calls FS_Option_Manager::set_option() and store(), which reaches WordPress update_option(). The object supplies the option name and value. In the lab, one object wrote a valid wp_user_roles array with elevated Subscriber capabilities. A second object wrote an additional registration setting through the same chain.

WordPress sanitizes users_can_register with absint(). In the tested payload, the option manager writes an array containing an enabled value; WordPress converts the non-empty array to 1. This is an impact extension of the same object-injection path, not a separate vulnerability.

CVE-2026-115806 Best CTEM platform

Figure 1. The 2.2.1 unserialize and property-trimming path alongside the 2.2.2 allowed-classes wrapper.

Version 2.2.2 replaces the direct call with PrimeMoverBridgeIO::unserialize(). On PHP 7 and later, the wrapper restricts allowed classes to stdClass, preventing the Freemius gadget from being instantiated. The wrapper also has a legacy-PHP check that rejects serialized object and custom-serialization markers. The official changelog describes this as hardening against object injection.

6. Risk

The demonstrated result is privilege escalation through WordPress option changes, not a web shell or direct PHP code execution. The new account remained labeled Subscriber, but the modified role definition granted manage_options and other capabilities. It could open General Settings; the evidence does not establish every capability of a normal Administrator account.

The exploit is stored and requires an administrator-triggered restore. An attacker needs no account to submit the comment, but the restore is a required trigger in the reproduced path. After the extended payload enables registration, an attacker can create a new account through WordPress’s public registration flow and receive the modified default Subscriber role.

Comment moderation alone is not a reliable defense: the lab’s importer processed a comment with approved=0 because it scanned stored database rows. The principal exposure is the combination of a vulnerable plugin, a writable public comment surface, and an administrator running the relevant restore workflow.

7. Mitigation

  • Update Prime Mover to 2.2.2 or later. This is the vendor-listed fix; verify the installed plugin version after updating.
  • If an update is not immediately possible, deactivate and remove the plugin where operationally feasible. Removing the active deserialization sink does not remove previously stored comments; review them separately.
  • Restrict migration restores to trusted administrators and verified packages. Treat restore operations as privileged input processing while the plugin is vulnerable.
  • Review comments and option integrity. Look for long base64 comment bodies that decode to PHP serialized objects, unexpected changes to wp_user_roles or users_can_register, new accounts around a restore, and unexplained role capability changes.
  • Do not rely on moderation status alone. A held comment remains in the database and may still be seen by a plugin routine that scans comment rows.

8. EXPLOIT IMPLEMENTATION

Attack Scenario

The test followed one stored-comment path: submit a base64-encoded serialized object through a public comment form, invoke the real importer search-and-replace entry point, then verify the resulting options and account permissions. The lab used WordPress 7.1 (patch level not recorded), PHP 8.3.36, MariaDB 11.8.9, and Prime Mover 2.2.1 or 2.2.2. The WordPress admin screenshot shows an update notice for 7.1.3. Northstar Group is a fictional site in an isolated, self-controlled lab; names shown are test accounts.

The plugin’s factory-built PrimeMoverImporter, its authorization state, and PrimeMoverSearchReplace::load() were exercised. The reproduction invoked the search-and-replace stage directly in an admin/AJAX context; it did not automate the full admin-UI package export, upload, and import sequence. The figures document the test stages; the comment-submission and importer-trigger captures are from separate runs.

Exploitation

1. Submit the serialized test payload as a comment on a public post with comments enabled. The unauthenticated request returns HTTP 302; the stored comment hash matches the submitted payload. The captured comment was unapproved.

CVE-2026-115806 Best CTEM platform

Figure 2. Cropped capture of the public post and its open comment form, the unauthenticated storage path.

CVE-2026-115806 Best CTEM platform

Figure 3. The comment POST returned 302; the stored content hash matched the payload and approved=0.

2. Record the baseline, then invoke the importer’s search-and-replace stage on the stored row. The vulnerable run used the real factory-built importer with authorization confirmed. A pre-existing Subscriber received HTTP 403 on General Settings before the trigger.

CVE-2026-115806 Best CTEM platform

Figure 4. A pre-existing Subscriber is denied access to General Settings before the payload is triggered.

CVE-2026-115806 Best CTEM platform

Figure 5. The 2.2.1 importer processes the stored row and reports elevated Subscriber capabilities and registration enabled.

3. Verify the option changes and account impact. The extended payload sets users_can_register=1 and changes the Subscriber role definition. The public form then creates an account whose role label remains Subscriber but whose capabilities include manage_options.

CVE-2026-115806 Best CTEM platform

Figure 6. Public registration is available after the restore-stage option change.

CVE-2026-115806 Best CTEM platform

Figure 7. WordPress accepts registration and displays its email-confirmation page.

The lab did not provide email delivery. After public registration, WP-CLI set a known password so login could be verified. The logged test reached General Settings with HTTP 200; the browser capture shows the same result in a separate run, using a different account name.

CVE-2026-115806 Best CTEM platform

Figure 8. A newly registered account opens General Settings, demonstrating access to a privileged page.

4. Run the control on Prime Mover 2.2.2. The stored row is present (comment_id 35), and the tested role and registration options remain unchanged. In the terminal output, row_bytes is strlen(comment_content): 6,592 bytes here, versus 6,308 in Figure 5. The differing lengths mean the captures do not establish byte-identical comment content; registration remained disabled.

CVE-2026-115806 Best CTEM platform

Figure 9. The patched 2.2.2 path leaves the tested role and registration settings unchanged.

CVE-2026-115806  CTEM

Figure 10. The site home page renders normally after the patched control run.

Observed Results

Check 2.2.1 2.2.2
Single-object role payload Subscriber capabilities elevated No role elevation observed
Two-object role and registration payload Role elevated; registration enabled Neither tested option changed
Public registration after trigger New Subscriber had manage_options; General Settings returned 200 Registration remained disabled

Two controls on 2.2.1 left the role unchanged: a serialized array without an object, and an object payload without the matching site URL, which the search-string check skipped. These results demonstrate the vulnerable and fixed code paths under the lab conditions above. The full administrator-facing package export/upload/import sequence was not driven end to end; production restore reaches the importer stage through that orchestration.

See how SAFE transforms your CTEM Unified exposure visibility, AI-driven prioritization, and quantified risk in business terms. Built for enterprise scale.