CVE-2026-1268

Dynamic Widget Content <= 1.3.6 - Authenticated (Contributor+) Stored Cross-Site Scripting via Widget Content Field

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

Description

The Dynamic Widget Content plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the widget content field in the Gutenberg editor sidebar in all versions up to, and including, 1.3.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.3.6
PublishedFebruary 4, 2026
Last updatedFebruary 5, 2026
Affected plugindynamic-widget-content

Source Code

WordPress.org SVN
Research Plan
Unverified

## Vulnerability Research Plan: CVE-2026-1268 - Dynamic Widget Content Stored XSS ### 1. Vulnerability Summary The **Dynamic Widget Content** plugin (<= 1.3.6) contains a Stored Cross-Site Scripting (XSS) vulnerability. The flaw exists because the plugin fails to sanitize and escape user-supplied i…

Show full research plan

Vulnerability Research Plan: CVE-2026-1268 - Dynamic Widget Content Stored XSS

1. Vulnerability Summary

The Dynamic Widget Content plugin (<= 1.3.6) contains a Stored Cross-Site Scripting (XSS) vulnerability. The flaw exists because the plugin fails to sanitize and escape user-supplied input entered into the "Widget Content" field within the Gutenberg editor's sidebar. This field is intended to allow users to define dynamic content for widgets, but because the input is saved as post metadata and subsequently rendered on the frontend without proper security filtering (like wp_kses or esc_html), a user with Contributor-level permissions or higher can inject malicious JavaScript.

2. Attack Vector Analysis

  • Endpoint: WordPress REST API Post endpoint: /wp/v2/posts/{id} or /wp/v2/pages/{id}.
  • Vulnerable Parameter: meta object containing the plugin's specific meta key (likely dwc_widget_content or _dwc_widget_content - inferred).
  • Authentication: Contributor-level access or higher is required. Contributors can create and edit their own posts, giving them access to the Gutenberg editor and its sidebar components.
  • Preconditions: The plugin must be active, and a post must exist (or be created) where the dynamic widget content is assigned.

3. Code Flow

  1. Input (JS): In the Gutenberg editor, the plugin registers a PluginSidebar or InspectorControls component. When a user types into the "Widget Content" text area, the state is updated and prepared for saving.
  2. Storage (REST API): Upon clicking "Save" or "Update" in WordPress, a POST request is sent to /wp/v2/posts/{id}. If the plugin has registered its meta field using register_post_meta with 'show_in_rest' => true, the raw XSS payload is saved into the wp_postmeta table.
  3. Processing (PHP): The plugin likely uses a filter such as the_content or a specific widget rendering hook (e.g., dynamic_sidebar_params or a shortcode callback) to retrieve this meta value.
  4. Sink (PHP): The retrieved meta value is output directly to the page:
    // Predicted vulnerable code pattern
    $content = get_post_meta( get_the_ID(), 'dwc_widget_content', true );
    echo $content; // MISSING: esc_html(), wp_kses(), or similar
    

4. Nonce Acquisition Strategy

To update post metadata via the REST API, the _wpnonce for the wp_rest action is required.

  1. Create Content: The agent will create a post as a Contributor.
  2. Access Editor: Use browser_navigate to go to the edit page for that post: /wp-admin/post.php?post={ID}&action=edit.
  3. Extract Nonce: The WordPress REST API nonce is globally available in the Gutenberg editor via the wpApiSettings object.
    • Tool: browser_eval
    • Script: window.wpApiSettings.nonce
  4. Identify Meta Key: If the exact meta key is unknown, the agent will inspect the wp.data store in the browser console:
    • Script: wp.data.select('core/editor').getCurrentPost().meta

5. Exploitation Strategy

  1. Authentication: Log in as a user with the Contributor role.
  2. Target Selection: Create a new post to get a valid Post ID.
  3. Nonce Retrieval: Navigate to the editor and extract the REST nonce using browser_eval.
  4. Payload Injection: Perform an http_request (POST) to the REST API to update the post's metadata with the XSS payload.
    • Method: POST
    • URL: /wp-json/wp/v2/posts/{ID}
    • Headers:
      • Content-Type: application/json
      • X-WP-Nonce: {EXTRACTED_NONCE}
    • Body:
      {
        "meta": {
          "dwc_widget_content": "<script>alert('CVE-2026-1268_XSS')</script>"
        }
      }
      
  5. Trigger: Navigate to the public URL of the modified post.

6. Test Data Setup

  • User: A user with username contributor_user and role contributor.
  • Post: A post titled "XSS Test" created by contributor_user.
  • Plugin Config: Ensure Dynamic Widget Content is active. No specific internal settings are usually required as the sidebar is enabled by default for posts.

7. Expected Results

  • The REST API should return a 200 OK response confirming the update of the post meta.
  • Upon navigating to the post frontend, the browser should execute the JavaScript, resulting in an alert box with CVE-2026-1268_XSS.
  • The page source should show the raw <script> tag within the widget area or content area.

8. Verification Steps

  1. Check Database: Use WP-CLI to verify the payload is stored in the metadata.
    • wp post meta get {ID} dwc_widget_content
  2. Verify Unsanitized Output: Use http_request (GET) on the post URL and check if the payload is escaped.
    • Check if <script> appears as &lt;script&gt; (safe) or <script> (vulnerable).
  3. Context Check: Verify the XSS executes in a standard browser environment using browser_navigate.

9. Alternative Approaches

  • If REST API is restricted: Attempt to save the payload via the standard admin-ajax.php or post.php save routine by intercepting the form submission.
  • If dwc_widget_content is not the key: Use grep -r "update_post_meta" . in the plugin directory to find the actual meta key used to save sidebar data.
  • Shortcode Injection: If the sidebar input is reflected in a shortcode, try injecting the payload via the post content: [dwc_render_widget content="<img src=x onerror=alert(1)>"] (inferred shortcode).
Research Findings
Static analysis — not yet PoC-verified

Summary

The Dynamic Widget Content plugin for WordPress (up to 1.3.6) is vulnerable to Stored Cross-Site Scripting via the 'Widget Content' field. Authenticated users with Contributor-level permissions or higher can inject malicious JavaScript into post metadata through the Gutenberg editor sidebar, which executes when the post is viewed because the input is not sanitized upon storage and the output is not escaped during rendering.

Vulnerable Code

// File: dynamic-widget-content.php (likely location)
// Meta registration allowing unsanitized input via REST API
register_post_meta( 'post', 'dwc_widget_content', array(
    'show_in_rest' => true,
    'single' => true,
    'type' => 'string',
) );

---

// Rendering logic failing to escape output
// Predicted vulnerable code pattern in a filter or widget callback
$content = get_post_meta( get_the_ID(), 'dwc_widget_content', true );
echo $content; // MISSING: esc_html(), wp_kses(), or similar sanitization

Security Fix

--- a/dynamic-widget-content.php
+++ b/dynamic-widget-content.php
@@ -10,6 +10,7 @@
     register_post_meta( 'post', 'dwc_widget_content', array(
         'show_in_rest' => true,
         'single' => true,
         'type' => 'string',
+        'sanitize_callback' => 'wp_kses_post',
     ) );
 }
 
@@ -25,5 +26,5 @@
 function dwc_render_widget_content( $content ) {
     $meta_content = get_post_meta( get_the_ID(), 'dwc_widget_content', true );
     if ( ! empty( $meta_content ) ) {
-        echo $meta_content;
+        echo wp_kses_post( $meta_content );
     }

Exploit Outline

The exploit requires an authenticated user with at least Contributor-level access to the WordPress dashboard. 1. Log in as a Contributor and create a new post to obtain a valid Post ID. 2. Access the Gutenberg editor for the newly created post to retrieve the WordPress REST API nonce from the `wpApiSettings.nonce` JavaScript object. 3. Identify the vulnerable meta key (e.g., `dwc_widget_content`) used by the plugin for the sidebar content field. 4. Send an authenticated HTTP POST request to the WordPress REST API endpoint `/wp-json/wp/v2/posts/{ID}`. 5. Include the payload in the `meta` object of the JSON body: `{ "meta": { "dwc_widget_content": "<script>alert('XSS')</script>" } }`. 6. The payload is stored in the database. When any user (including administrators) views the public post, the script will execute in their browser context.

Check if your site is affected.

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