CVE-2026-2020

JS Archive List <= 6.1.7 - Authenticated (Contributor+) PHP Object Injection via 'included' Shortcode Attribute

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

Description

The JS Archive List plugin for WordPress is vulnerable to PHP Object Injection in all versions up to, and including, 6.1.7 via the 'included' shortcode attribute. This is due to the deserialization of untrusted input supplied via the 'included' parameter of the plugin's shortcode. 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 6, 2026
Last updatedMarch 7, 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-2020 (JS Archive List PHP Object Injection) ## 1. Vulnerability Summary The **JS Archive List** plugin (up to 6.1.7) is vulnerable to **PHP Object Injection**. The vulnerability occurs because the plugin takes the `included` attribute from its shortcode (or bl…

Show full research plan

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

1. Vulnerability Summary

The JS Archive List plugin (up to 6.1.7) is vulnerable to PHP Object Injection. The vulnerability occurs because the plugin takes the included attribute from its shortcode (or block equivalent) and passes it directly to the PHP unserialize() function without proper validation or sanitization. Since authenticated users with the Contributor role can create or edit posts and insert shortcodes, they can supply a serialized PHP object payload. If a suitable PHP Object Prototyping (POP) chain exists in the WordPress environment (via other plugins or themes), this can lead to Remote Code Execution (RCE), arbitrary file deletion, or sensitive data exposure.

2. Attack Vector Analysis

  • Entry Point: WordPress Shortcode (likely [js-archive-list] or [js_archive_list]).
  • Vulnerable Attribute: included.
  • Authentication Level: Contributor or higher (any role with edit_posts capability).
  • Endpoint: Post/Page rendering (frontend).
  • Mechanism: The unserialize() sink is triggered when WordPress parses and renders the shortcode within a post's content.

3. Code Flow (Inferred from Description)

  1. Registration: The plugin registers a shortcode using add_shortcode() or a dynamic block using register_block_type() with a render_callback.
  2. Parsing: When a user visits a post containing the shortcode/block, WordPress calls the associated callback function.
  3. Extraction: The callback function receives an $atts (attributes) array.
  4. Sink: Inside the callback, code similar to the following exists:
    // Inferred vulnerable code path
    $included_data = $atts['included'];
    if (!empty($included_data)) {
        $data = unserialize($included_data); // <--- SINK
    }
    
  5. Execution: The unserialize() call triggers __wakeup() or __destruct() methods of the injected object.

4. Nonce Acquisition Strategy

This vulnerability is triggered during the rendering of a post, not a specific AJAX or REST action that requires a nonce. However, to create the post as a Contributor, the agent must interact with the WordPress editor.

  1. Shortcode Identification:
    The agent should first identify the exact shortcode name:
    grep -rn "add_shortcode" /var/www/html/wp-content/plugins/jquery-archive-list-widget/
    
  2. Payload Injection:
    Since we are testing in an environment where we have CLI access, the most efficient way to "place" the payload is via wp post create. This bypasses the need for browser-based nonce extraction for the editor.

5. Exploitation Strategy

Step 1: Locate the Sink

Confirm the location of the unserialize call to understand the attribute handling.

grep -rn "unserialize" /var/www/html/wp-content/plugins/jquery-archive-list-widget/

Step 2: Create a Test Payload

Since no POP chain is present in the plugin itself, use a simple class that exists in WordPress core or one that triggers a visible PHP notice/error upon unserialization to confirm the injection. For instance, injecting a stdClass or a non-existent class.

Step 3: Inject and Trigger

  1. Create a Post: Use wp-cli to create a post containing the shortcode with the payload.

    • Shortcode: [js_archive_list included='O:8:"stdClass":0:{}'] (Replace js_archive_list with the actual shortcode found in Step 1).
    • Note: Ensure the payload is correctly escaped for the CLI.
  2. Access the Post: Perform an unauthenticated (or authenticated) GET request to the newly created post's URL.

HTTP Request Template

GET /?p=[POST_ID] HTTP/1.1
Host: localhost:8080

6. Test Data Setup

  1. User Creation:
    wp user create attacker attacker@example.com --role=contributor --user_pass=password
    
  2. Post Creation (Vulnerable Payload):
    # Assuming the shortcode is [js_archive_list]
    wp post create --post_type=post --post_status=publish --post_title="Exploit Test" \
      --post_content='[js_archive_list included="O:8:\"WP_HTML_Token\":1:{s:5:\"nodes\";s:4:\"test\";}"]' \
      --user=attacker
    

7. Expected Results

  • Detection via Error: If WP_DEBUG is on, the application might throw an error or notice if the serialized string is malformed or if the class exists but lacks certain properties.
  • Detection via Logic: If using a specialized POP chain (e.g., GuzzleHttp\Cookie\FileCookieJar if available), a file would be created or modified on the system.
  • Success Indicator: Confirmation that the unserialize() function was called with user-provided input.

8. Verification Steps

  1. Audit Logs: Check the PHP error log for any notices related to unserialize() or object instantiation.
    tail -f /var/www/html/wp-content/debug.log
    
  2. Source Code Confirmation: Verify the code at the identified line number in the plugin. If the line is $data = unserialize($atts['included']);, the vulnerability is confirmed.

9. Alternative Approaches

If the plugin uses a Gutenberg block instead of a standard shortcode:

  1. Identify the block name from build/block.json (found in source: js-archive-list/archive-widget).
  2. The payload must be inserted into the post content in Gutenberg comment format:
    <!-- wp:js-archive-list/archive-widget {"included":"O:8:\"stdClass\":0:{}"} /-->
    
  3. Use wp post create with this block content and then visit the page.
Research Findings
Static analysis — not yet PoC-verified

Summary

The JS Archive List plugin for WordPress is vulnerable to PHP Object Injection in versions up to 6.1.7. This occurs because the plugin's shortcode handler passes the 'included' attribute directly to the PHP unserialize() function without any validation, allowing Contributor-level users to inject malicious PHP objects.

Vulnerable Code

// In the shortcode rendering logic (likely jquery-archive-list-widget.php)

$included = isset( $atts['included'] ) ? $atts['included'] : '';

if ( ! empty( $included ) ) {
    // The plugin takes the 'included' attribute directly from the shortcode attributes
    // and passes it to the unserialize sink.
    $included = unserialize( $included );
}

Security Fix

--- a/jquery-archive-list-widget.php
+++ b/jquery-archive-list-widget.php
@@ -1,5 +1,5 @@
-        if ( ! empty( $included ) ) {
-            $included = unserialize( $included );
-        }
+        if ( ! empty( $included ) ) {
+            $included = json_decode( $included, true );
+        }

Exploit Outline

The exploit requires an attacker with at least Contributor-level authentication, which allows them to create and edit posts. The attacker creates a new post and inserts the plugin's shortcode (e.g., [js_archive_list]) while including a serialized PHP object payload within the 'included' attribute. When the post is saved and then viewed (rendered) by any user, the WordPress shortcode parser executes the plugin's callback function. This function retrieves the 'included' attribute value and passes it to the PHP unserialize() function, triggering the injection. If a suitable PHP Object Prototyping (POP) chain exists in the site's environment (via other plugins or themes), this can lead to remote code execution, file deletion, or sensitive data access.

Check if your site is affected.

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