CVE-2026-49769

wpForo Forum <= 3.1.0 - Unauthenticated PHP Object Injection

highDeserialization of Untrusted Data
8.1
CVSS Score
8.1
CVSS Score
high
Severity
3.1.1
Patched in
5d
Time to patch

Description

The wpForo Forum plugin for WordPress is vulnerable to PHP Object Injection in versions up to, and including, 3.1.0 via deserialization of untrusted input. This makes it possible for unauthenticated attackers to inject a PHP Object. No known POP chain is present in the vulnerable software. If a POP chain is present via an additional plugin or theme installed on the target system, it could allow the attacker to delete arbitrary files, retrieve sensitive data, or execute code.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H
Attack Vector
Network
Attack Complexity
High
Privileges Required
None
User Interaction
None
Scope
Unchanged
High
Confidentiality
High
Integrity
High
Availability

Technical Details

Affected versions<=3.1.0
PublishedJune 4, 2026
Last updatedJune 8, 2026
Affected pluginwpforo

What Changed in the Fix

Changes introduced in v3.1.1

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

This research plan outlines the steps to verify and exploit an unauthenticated PHP Object Injection vulnerability in the **wpForo Forum** plugin (version <= 3.1.0). ## 1. Vulnerability Summary - **Vulnerability:** Unauthenticated PHP Object Injection - **CVE ID:** CVE-2026-49769 - **Affected Compon…

Show full research plan

This research plan outlines the steps to verify and exploit an unauthenticated PHP Object Injection vulnerability in the wpForo Forum plugin (version <= 3.1.0).

1. Vulnerability Summary

  • Vulnerability: Unauthenticated PHP Object Injection
  • CVE ID: CVE-2026-49769
  • Affected Component: wpforo\classes\Members class, specifically the decode() method and its interaction with member session/cookie handling.
  • Sink: unserialize() or maybe_unserialize() (inferred to be within the truncated portion of classes/Members.php).
  • Source: Untrusted user input provided via a cookie (likely wpf_member_data or wpforo_member) or a request parameter processed during the init hook sequence.
  • Impact: If a POP (Property-Oriented Programming) chain is present on the system (via other plugins/themes or WordPress core), an attacker can achieve Remote Code Execution (RCE), arbitrary file deletion, or sensitive data retrieval.

2. Attack Vector Analysis

  • Endpoint: Any WordPress frontend page (the vulnerability triggers during the init hook).
  • Trigger Hook: add_action( 'init', function() { if( ! WPF()->current_userid ) $this->init_current_user(); } ); in classes/Members.php.
  • Preconditions:
    • Plugin wpForo Forum version <= 3.1.0 installed and active.
    • An unauthenticated session (guest user).
  • Payload Location: A specific cookie (likely wpforo_member) that the plugin attempts to decode to restore guest session data.

3. Code Flow Trace

  1. Initialization: Upon any request, WordPress fires the init hook.
  2. Hook Execution: The anonymous function registered in wpforo\classes\Members::init_hooks() executes.
  3. Condition Check: If the user is not logged in (! WPF()->current_userid), it calls $this->init_current_user().
  4. Session Restoration: init_current_user() (inferred) checks for a session cookie (e.g., $_COOKIE['wpforo_member']) to identify the guest or restore "fields" data.
  5. Vulnerable Sink: The data from the cookie is passed to wpforo\classes\Members::decode($member).
  6. Deserialization: Inside decode() (or a subsequent call to a metadata handler), the code performs unserialize() or maybe_unserialize() on keys within the member array (e.g., $member['fields']).

4. Nonce Acquisition Strategy

Because the vulnerability resides in the init hook sequence used for session restoration of unauthenticated users, no WordPress nonce is required for the primary exploitation path. The code executes before nonce verification layers are typically reached.

5. Exploitation Strategy

Step 1: Payload Generation

Since no POP chain is present in wpForo itself, we will use a standard WordPress Core POP chain to demonstrate the vulnerability. We will use the Requests_Utility_FilteredIterator chain (present in WordPress < 6.4) to trigger a function call.

Payload Concept:

// Example: Triggering phpinfo() or a simple file write if a chain exists
// This is a conceptual payload for a common WP Core chain
$object = new Requests_Utility_FilteredIterator([ 'phpinfo', '1' ], 'passthru');
$serialized_payload = serialize($object);

Step 2: Request Construction

The payload must be placed in the cookie that init_current_user() processes. We will use wpforo_member (common for this plugin version) and base64-encode the serialized string.

HTTP Request:

  • Method: GET
  • URL: http://localhost:8080/
  • Headers:
    • Cookie: wpforo_member=[BASE64_ENCODED_SERIALIZED_OBJECT]

6. Test Data Setup

  1. Plugin Installation: Install wpForo version 3.1.0.
  2. Environment Check: Ensure the environment is running a PHP version compatible with the plugin (>= 7.1).
  3. No Auth Required: Ensure you are testing as a logged-out guest.

7. Expected Results

  • Success: The application processes the cookie and triggers the deserialization. If using a POP chain like Requests_Utility_FilteredIterator with phpinfo, the output of phpinfo() should appear in the response, or the system should exhibit behavior corresponding to the injected object's magic methods (__destruct, __wakeup).
  • Failure: The page loads normally without executing the payload, or a 500 error occurs due to a malformed serialized string (indicating the sink was reached but the payload was invalid).

8. Verification Steps

After sending the HTTP request, verify the injection via:

  1. Server Logs: Check for PHP errors related to unserialize() or class instantiation failures.
  2. Manual Check: If the payload triggers a visible change (e.g., creating a file or modifying user meta), use wp-cli to verify:
    wp eval 'echo "Target file exists: " . (file_exists("pwned.txt") ? "Yes" : "No");'
    

9. Alternative Approaches

If the cookie-based init path fails, investigate the following alternative entry points:

  • AJAX Action: wp_ajax_nopriv_wpforo_get_member. Check if this action accepts a member parameter that is passed to decode().
  • Parameter wpfval: In some wpForo versions, URL parameters passed through the wpfval() helper were automatically deserialized if they appeared to be serialized strings. Test /?wpforo_member=[PAYLOAD].

Note: If wpforo_member is not the correct cookie name, use browser_navigate to visit the forum and inspect the Set-Cookie headers or the window.wpforo_obj JavaScript object to find the exact cookie name used for guest session tracking.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.