CVE-2026-32513

JS Archive List <= 6.1.7 - Authenticated (Contributor+) PHP Object Injection

highDeserialization of Untrusted Data
7.5
CVSS Score
7.5
CVSS Score
high
Severity
6.2.0
Patched in
8d
Time to patch

Description

The JS Archive List plugin for WordPress is vulnerable to PHP Object Injection in versions up to, and including, 6.1.7 via deserialization of untrusted input [from the vulnerable parameter?|in the vulnerable function?]. This makes it possible for authenticated attackers, with contributor-level access and above, 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:L/UI:N/S:U/C:H/I:H/A:H
Attack Vector
Network
Attack Complexity
High
Privileges Required
Low
User Interaction
None
Scope
Unchanged
High
Confidentiality
High
Integrity
High
Availability

Technical Details

Affected versions<=6.1.7
PublishedMarch 20, 2026
Last updatedMarch 27, 2026

What Changed in the Fix

Changes introduced in v6.2.0

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-32513 (JS Archive List Object Injection) ## 1. Vulnerability Summary The **JS Archive List** plugin (versions <= 6.1.7) is vulnerable to **PHP Object Injection** via the deserialization of untrusted user input. The vulnerability likely resides in a REST API en…

Show full research plan

Exploitation Research Plan: CVE-2026-32513 (JS Archive List Object Injection)

1. Vulnerability Summary

The JS Archive List plugin (versions <= 6.1.7) is vulnerable to PHP Object Injection via the deserialization of untrusted user input. The vulnerability likely resides in a REST API endpoint or an AJAX handler that processes block attributes. Specifically, the plugin's Gutenberg block (js-archive-list/archive-widget) sends its configuration (attributes) to the server to fetch archive data. If the server-side logic applies unserialize() or maybe_unserialize() to any of these attributes (most likely the categories array or a legacy configuration string) without proper validation, an authenticated attacker with Contributor-level permissions can inject a PHP POP chain.

2. Attack Vector Analysis

  • Endpoint: WordPress REST API /wp-json/jalw/v1/archive (inferred from build/index.js).
  • Vulnerable Parameter: categories (or potentially config if attributes are passed as a single string).
  • Authentication: Authenticated (Contributor+). Contributors can access the Gutenberg editor, which triggers the REST API calls used by the block.
  • Preconditions: The attacker must have a valid login with at least edit_posts capability (Contributor).

3. Code Flow

  1. Frontend Trigger: In the Gutenberg editor, the JsArchiveList component (build/index.js) calls the loadYears(config) function.
  2. API Call: This function uses wp-api-fetch to send a request to /jalw/v1/archive.
  3. Server-Side Registration: The plugin registers this route using register_rest_route( 'jalw/v1', '/archive', ... ) (likely in a file like includes/api.php or the main plugin file).
  4. Vulnerable Sink: The callback function for this route (e.g., get_archive_data) retrieves parameters from the $request.
  5. Deserialization: The code likely performs a check like:
    $categories = $request->get_param('categories');
    if (is_string($categories)) {
        $categories = unserialize($categories); // SINK
    }
    
    Or uses maybe_unserialize() on a parameter that the attacker can provide as a serialized string.

4. Nonce Acquisition Strategy

The REST API endpoint requires a wp_rest nonce for authentication. This nonce is typically available in the WordPress admin dashboard for any logged-in user.

  1. Access Editor: Log in as a Contributor and navigate to the "New Post" page (/wp-admin/post-new.php).
  2. Extract Nonce: The wp_rest nonce is localized in the wpApiSettings JavaScript object.
  3. Agent Tooling:
    • Use browser_navigate to go to http://localhost:8080/wp-admin/post-new.php.
    • Use browser_eval to extract the nonce:
      window.wpApiSettings.nonce
      

5. Exploitation Strategy

Step 1: Discover the exact REST parameter

The researcher should first confirm the REST API structure by inspecting the plugin's registration of jalw/v1/archive.

grep -rn "register_rest_route" . --include="*.php"

Step 2: Craft Payload

Since no POP chain is present in the plugin, we use a generic "check" payload to confirm the injection. If a specific chain is required for RCE, common WordPress core chains (like WP_HTML_Token in newer versions or Requests_Utility_FilteredIterator) can be attempted.

Confirming Payload:
O:8:"stdClass":0:{} (A simple standard class object).

Step 3: Execute Request

Send an authenticated request to the REST API with the serialized payload.

HTTP Request (via http_request tool):

  • Method: GET (or POST if the route requires it)
  • URL: http://localhost:8080/wp-json/jalw/v1/archive?categories=O:8:"stdClass":0:{}
  • Headers:
    • X-WP-Nonce: [EXTRACTED_NONCE]
    • Cookie: [CONTRIBUTOR_COOKIES]

6. Test Data Setup

  1. User Creation: Create a user with the contributor role.
    wp user create attacker attacker@example.com --role=contributor --user_pass=password
    
  2. Post Context: As the contributor, create a draft post to ensure the editor environment is active.
    wp post create --post_type=post --post_status=draft --post_author=[ATTACKER_ID] --post_title="Exploit Test"
    

7. Expected Results

  • Success Criteria: The server processes the request. If a POP chain is used that triggers an observable effect (e.g., creating a file or sending a DNS request), that effect is observed.
  • Error Side-Effect: If unserialize() is called on an invalid object, PHP may throw a notice or warning. If a valid object is injected, the REST response might return an error if the code expects an array but receives an object (e.g., foreach() argument must be of type array).

8. Verification Steps

  1. Log Analysis: Check the PHP error logs for unserialize() errors or signs of object instantiation.
    tail -f /var/www/html/wp-content/debug.log
    
  2. Dynamic Analysis: Use a payload that triggers a recognizable function (if a chain is found) or use the http_request tool to monitor the response status. A 500 Internal Server Error referencing a "broken object" or "class not found" often confirms deserialization was attempted.

9. Alternative Approaches

If the REST API does not directly expose the vulnerability:

  1. Block Rendering: Contributors can save posts with blocks. If the render_callback for the archive-widget block uses unserialize on attributes, the attacker can save a post containing:
    <!-- wp:js-archive-list/archive-widget {"categories":"O:8:\"Payload\":0:{}"} /-->
    
    And then view the post (or the preview) to trigger the injection.
  2. AJAX: Check for wp_ajax_ actions registered by the plugin using:
    grep -rn "wp_ajax" . --include="*.php"
    
    And check if those handlers process attributes.
Research Findings
Static analysis — not yet PoC-verified

Summary

The JS Archive List plugin for WordPress is vulnerable to PHP Object Injection via deserialization of untrusted input in the '/wp-json/jalw/v1/archive' REST API endpoint. Authenticated attackers with Contributor-level permissions can exploit this by submitting a serialized PHP object as a block attribute, potentially leading to remote code execution if a suitable POP chain is available on the target system.

Security Fix

Only in /home/deploy/wp-safety.org/data/plugin-versions/jquery-archive-list-widget/6.1.7/assets: public
diff -ru /home/deploy/wp-safety.org/data/plugin-versions/jquery-archive-list-widget/6.1.7/build/block.json /home/deploy/wp-safety.org/data/plugin-versions/jquery-archive-list-widget/6.2.0/build/block.json
--- /home/deploy/wp-safety.org/data/plugin-versions/jquery-archive-list-widget/6.1.7/build/block.json	2026-01-12 21:31:44.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/jquery-archive-list-widget/6.2.0/build/block.json	2026-02-22 14:24:24.000000000 +0000
@@ -7,7 +7,7 @@
   "category": "widgets",
   "icon": "list-view",
   "description": "A block for displaying an archive list with some effects.",
-  "textdomain": "jalw_i18n",
+  "textdomain": "jquery-archive-list-widget",
   "editorScript": "file:index.js",
   "editorStyle": "file:index.css",
   "viewScript": "file:view.js",
   "style": "file:style-index.css",
diff -ru /home/deploy/wp-safety.org/data/plugin-versions/jquery-archive-list-widget/6.1.7/build/index.asset.php /home/deploy/wp-safety.org/data/plugin-versions/jquery-archive-list-widget/6.2.0/build/index.asset.php
--- /home/deploy/wp-safety.org/data/plugin-versions/jquery-archive-list-widget/6.1.7/build/index.asset.php	2026-01-12 21:31:44.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/jquery-archive-list-widget/6.2.0/build/index.asset.php	2026-02-22 14:24:24.000000000 +0000
@@ -1 +1 @@
-<?php return array('dependencies' => array('react-jsx-runtime', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-date', 'wp-element', 'wp-i18n'), 'version' => 'b60bb6b41da71dd2fe96');
+<?php return array('dependencies' => array('react-jsx-runtime', 'wp-api-fetch', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-data', 'wp-date', 'wp-element', 'wp-i18n'), 'version' => '44bdc6c75951c365267c');
... (truncated)

Exploit Outline

1. Authenticate to the WordPress site as a user with at least Contributor-level permissions. 2. Obtain a valid REST API nonce (wp_rest) by inspecting the 'wpApiSettings.nonce' variable in the dashboard's browser console. 3. Identify the REST API endpoint at '/wp-json/jalw/v1/archive', which is used by the plugin to fetch archive data for its Gutenberg block. 4. Craft a malicious request to this endpoint, supplying a serialized PHP object (POP chain) to the 'categories' parameter (or other parameters that are processed as block attributes). 5. The server-side code receives the request and processes the attribute using a deserialization function (e.g., 'unserialize' or 'maybe_unserialize') on the untrusted string. 6. The injected object is instantiated, triggering the POP chain and allowing for arbitrary code execution, file deletion, or sensitive data retrieval, depending on available classes in the WordPress environment.

Check if your site is affected.

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