JS Archive List <= 6.1.7 - Authenticated (Contributor+) PHP Object Injection
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:HTechnical Details
<=6.1.7What Changed in the Fix
Changes introduced in v6.2.0
Source Code
WordPress.org SVN# 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 frombuild/index.js). - Vulnerable Parameter:
categories(or potentiallyconfigif 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_postscapability (Contributor).
3. Code Flow
- Frontend Trigger: In the Gutenberg editor, the
JsArchiveListcomponent (build/index.js) calls theloadYears(config)function. - API Call: This function uses
wp-api-fetchto send a request to/jalw/v1/archive. - Server-Side Registration: The plugin registers this route using
register_rest_route( 'jalw/v1', '/archive', ... )(likely in a file likeincludes/api.phpor the main plugin file). - Vulnerable Sink: The callback function for this route (e.g.,
get_archive_data) retrieves parameters from the$request. - Deserialization: The code likely performs a check like:
Or uses$categories = $request->get_param('categories'); if (is_string($categories)) { $categories = unserialize($categories); // SINK }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.
- Access Editor: Log in as a Contributor and navigate to the "New Post" page (
/wp-admin/post-new.php). - Extract Nonce: The
wp_restnonce is localized in thewpApiSettingsJavaScript object. - Agent Tooling:
- Use
browser_navigateto go tohttp://localhost:8080/wp-admin/post-new.php. - Use
browser_evalto extract the nonce:window.wpApiSettings.nonce
- Use
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(orPOSTif 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
- User Creation: Create a user with the
contributorrole.wp user create attacker attacker@example.com --role=contributor --user_pass=password - 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
- Log Analysis: Check the PHP error logs for
unserialize()errors or signs of object instantiation.tail -f /var/www/html/wp-content/debug.log - Dynamic Analysis: Use a payload that triggers a recognizable function (if a chain is found) or use the
http_requesttool to monitor the response status. A500 Internal Server Errorreferencing 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:
- Block Rendering: Contributors can save posts with blocks. If the
render_callbackfor thearchive-widgetblock usesunserializeon attributes, the attacker can save a post containing:
And then view the post (or the preview) to trigger the injection.<!-- wp:js-archive-list/archive-widget {"categories":"O:8:\"Payload\":0:{}"} /--> - AJAX: Check for
wp_ajax_actions registered by the plugin using:
And check if those handlers process attributes.grep -rn "wp_ajax" . --include="*.php"
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 @@ -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", @@ -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.