CVE-2026-7635

coreActivity: Activity Logging for WordPress <= 3.0 - Unauthenticated PHP Object Injection via 'user_agent' Log Meta Field

highDeserialization of Untrusted Data
8.1
CVSS Score
8.1
CVSS Score
high
Severity
3.1
Patched in
1d
Time to patch

Description

The coreActivity: Activity Logging for WordPress plugin for WordPress is vulnerable to PHP Object Injection in all versions up to, and including, 3.0. This is due to the plugin failing to validate or strip PHP serialization syntax from the User-Agent HTTP header before storing it in the logmeta table, and subsequently calling `maybe_unserialize()` on every retrieved `meta_value` in `query_metas()` without verifying the data was originally serialized by the application. This makes it possible for unauthenticated attackers to inject a crafted PHP serialized payload via the User-Agent header during any logged event (such as a failed login attempt), which, when an administrator views the Logs page, is deserialized and passed to `DeviceDetector::setUserAgent()`, triggering a Fatal TypeError that creates a persistent Denial of Service condition blocking administrator access to the Logs page entirely.

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.0
PublishedMay 12, 2026
Last updatedMay 13, 2026
Affected plugincoreactivity

What Changed in the Fix

Changes introduced in v3.1

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Research Plan: CVE-2026-7635 PHP Object Injection in coreActivity ## 1. Vulnerability Summary The **coreActivity: Activity Logging for WordPress** plugin (<= 3.0) is vulnerable to **unauthenticated PHP Object Injection**. The plugin captures the `User-Agent` HTTP header during logged events (e.g.…

Show full research plan

Research Plan: CVE-2026-7635 PHP Object Injection in coreActivity

1. Vulnerability Summary

The coreActivity: Activity Logging for WordPress plugin (<= 3.0) is vulnerable to unauthenticated PHP Object Injection. The plugin captures the User-Agent HTTP header during logged events (e.g., failed logins, 404s, or general activity) and stores it in the logmeta database table without sanitizing PHP serialization syntax (e.g., O:8:"...").

When an administrator views the Logs page, the plugin retrieves these values and calls maybe_unserialize() on every meta_value. Because the input was not sanitized during storage, an attacker can provide a serialized object string that is then instantiated. The resulting object is passed to DeviceDetector::setUserAgent(), which expects a string, causing a Fatal TypeError in PHP 8.x. This results in a persistent Denial of Service (DoS) for the Logs page.

2. Attack Vector Analysis

  • Endpoint: Any page that triggers a logged event. The most reliable unauthenticated target is wp-login.php (triggering a login failure event).
  • Vulnerable Parameter: User-Agent HTTP Request Header.
  • Authentication: None required (unauthenticated).
  • Preconditions:
    • The plugin must be active.
    • Event logging must be enabled (typically default for login failures).
    • The site must be running on PHP 8.x (to trigger the TypeError DoS).

3. Code Flow

  1. Ingestion: A request is made to the WordPress site.
  2. Capture: In Dev4Press\Plugin\CoreActivity\Log\Core::__construct(), the plugin populates cached_data['ua'] via $this->get_user_agent() (which reads $_SERVER['HTTP_USER_AGENT']).
  3. Logging Trigger: An event (like a failed login) calls Dev4Press\Plugin\CoreActivity\Log\Core::log().
  4. Processing: log() calls prepare_meta() and prepare_device($meta). The unsanitized User-Agent string is added to the $meta array.
  5. Storage: Dev4Press\Plugin\CoreActivity\Basic\DB::i()->log_event($data, $meta) is called. The meta_value (the malicious string) is written directly to the logmeta table.
  6. Retrieval (Admin Side): An administrator navigates to wp-admin/admin.php?page=coreactivity-logs.
  7. Deserialization: The display logic calls a retrieval function (likely query_metas()) which executes maybe_unserialize() on the stored meta_value.
  8. Sink: The resulting object (e.g., a stdClass object) is passed to DeviceDetector::setUserAgent().
  9. Fatal Error: PHP throws a TypeError because the method signature for setUserAgent requires a string, but an object was provided.

4. Nonce Acquisition Strategy

This vulnerability does not require a nonce for the injection phase.

  • The injection occurs via the User-Agent header during standard WordPress actions (like login) which are hooked by the plugin.
  • The plugin's logging mechanism runs automatically on hooks like wp_login_failed.
  • The DoS/Execution trigger occurs when the Admin visits the Logs page, which is a standard GET request to a known slug.

5. Exploitation Strategy

The goal is to inject a PHP object that triggers a TypeError when the administrator attempts to view the logs.

Injection Phase

  1. Target the login endpoint to ensure an event is logged.
  2. HTTP Request:
    POST /wp-login.php HTTP/1.1
    Host: victim.com
    Content-Type: application/x-www-form-urlencoded
    User-Agent: O:8:"stdClass":0:{}
    
    log=admin&pwd=wrongpassword&wp-submit=Log+In
    
    Note: O:8:"stdClass":0:{} is a simple serialized stdClass object.

Trigger Phase

  1. Log in as a WordPress Administrator.
  2. Navigate to the coreActivity Logs page.
  3. HTTP Request:
    GET /wp-admin/admin.php?page=coreactivity-logs HTTP/1.1
    Host: victim.com
    Cookie: [Admin Cookies]
    

6. Test Data Setup

  1. Install and activate coreActivity: Activity Logging for WordPress version 3.0.
  2. Ensure PHP 8.0+ is used in the test environment.
  3. Confirm logging is active (check the dashboard at /wp-admin/admin.php?page=coreactivity-dashboard).

7. Expected Results

  1. The log_event call will successfully write O:8:"stdClass":0:{} to the database meta table.
  2. Upon accessing the Logs page, the server will return a 500 Internal Server Error or a white screen.
  3. The PHP error log will contain:
    Fatal error: Uncaught TypeError: DeviceDetector\DeviceDetector::setUserAgent(): Argument #1 ($userAgent) must be of type string, stdClass given...

8. Verification Steps

  1. Database Check: Use WP-CLI to verify the injected value is in the database.
    wp db query "SELECT meta_value FROM wp_coreactivity_logmeta WHERE meta_value LIKE 'O:8:%';"
    
  2. Log Verification: Check the WordPress error log for the specific TypeError involving DeviceDetector.

9. Alternative Approaches

Remote Code Execution (RCE)

If the environment contains a usable POP chain (gadget), the vulnerability can be escalated from DoS to RCE.

  1. Analyze composer.lock for included libraries.
  2. erusev/parsedown and matomo/device-detector are present.
  3. Search for gadgets in dev4press/library (the plugin's custom shared library), specifically looking for __destruct, __wakeup, or __toString methods in the Dev4Press\v55 namespace.
  4. If a gadget is found, replace O:8:"stdClass":0:{} with the crafted gadget chain payload.
Research Findings
Static analysis — not yet PoC-verified

Summary

The coreActivity: Activity Logging for WordPress plugin (<= 3.0) is vulnerable to unauthenticated PHP Object Injection via the User-Agent HTTP header. The plugin stores the raw User-Agent string in the logmeta table and later retrieves it using maybe_unserialize() without validation, allowing attackers to inject crafted PHP objects that can lead to a Denial of Service (DoS) or potential Remote Code Execution (RCE).

Vulnerable Code

// core/log/Core.php
private function __construct() {
    $this->cached_data = array(
        'ip'          => IP::visitor( coreactivity_settings()->get( 'ip_visitor_forwarded' ) ),
        'remote_addr' => IP::visitor( false ),
        'server_ip'   => isset( $_SERVER['SERVER_ADDR'] ) ? IP::server() : '',
        'ua'          => $this->get_user_agent(), // Captures unsanitized User-Agent
        'referer'     => $this->get_referer(),
        // ...
    );
}

---

// core/log/Core.php
public function log( int $event_id, array $data = array(), array $meta = array() ) : int {
    // ...
    $data = $this->prepare_data( $event_id, $data );
    $meta = $this->prepare_meta( $meta ); // Injects 'ua' into $meta

    // ...
    $meta = $this->prepare_device( $meta );

    // ...
    $id = DB::i()->log_event( $data, $meta ); // Stores unsanitized User-Agent in DB
    // ...
}

Security Fix

--- a/core/log/Core.php
+++ b/core/log/Core.php
@@ -50,7 +50,7 @@
 			'ip'          => IP::visitor( coreactivity_settings()->get( 'ip_visitor_forwarded' ) ),
 			'remote_addr' => IP::visitor( false ),
 			'server_ip'   => isset( $_SERVER['SERVER_ADDR'] ) ? IP::server() : '',
-			'ua'          => $this->get_user_agent(),
+			'ua'          => sanitize_text_field($this->get_user_agent()),
 			'referer'     => $this->get_referer(),
 			'method'      => $this->get_request_method(),
 			'protocol'    => wp_get_server_protocol(),
--- a/core/basic/DB.php
+++ b/core/basic/DB.php
@@ -150,5 +150,5 @@
 	public function query_metas($log_id) {
-		// ...
-		$meta_value = maybe_unserialize($result->meta_value);
+		// Use a safer retrieval method that avoids automatic deserialization of user-provided strings
+		$meta_value = $result->meta_value;
 		// ...
 	}

Exploit Outline

The exploit is achieved by performing any action that triggers a logged event while supplying a malicious User-Agent string. 1. An unauthenticated attacker sends a request to an endpoint that triggers logging, such as a POST request to `wp-login.php` with incorrect credentials. 2. The request includes a crafted PHP serialized object (e.g., `O:8:"stdClass":0:{}`) within the `User-Agent` HTTP header. 3. The plugin captures this header and stores it directly in the `logmeta` database table as a `meta_value` associated with the log entry. 4. When a WordPress administrator navigates to the plugin's Logs page (`/wp-admin/admin.php?page=coreactivity-logs`), the plugin retrieves the stored meta values. 5. The plugin calls `maybe_unserialize()` on the retrieved data. Because the data is now a valid serialized object string, PHP instantiates the object. 6. On PHP 8.x, if the resulting object is passed to library functions expecting a string (like `DeviceDetector::setUserAgent`), it triggers a `Fatal TypeError`, effectively locking administrators out of the activity log page (Denial of Service).

Check if your site is affected.

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