[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fTebQ_MOMxCJkv-v_c1rcxU55-A2EJI5MFDkwrPOOVIA":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":28,"research_verified":29,"research_rounds_completed":30,"research_plan":31,"research_summary":32,"research_vulnerable_code":33,"research_fix_diff":34,"research_exploit_outline":35,"research_model_used":36,"research_started_at":37,"research_completed_at":38,"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":29,"poc_model_used":9,"poc_verification_depth":9,"source_links":39},"CVE-2026-3875","betterdocs-authenticated-contributor-stored-cross-site-scripting-via-shortcode-attributes","BetterDocs \u003C= 4.3.8 - Authenticated (Contributor+) Stored Cross-Site Scripting via Shortcode Attributes","The BetterDocs plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'betterdocs_feedback_form' shortcode in all versions up to, and including, 4.3.8. This is due to insufficient input sanitization and output escaping on user supplied shortcode 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.","betterdocs",null,"\u003C=4.3.8","4.3.9","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-04-15 18:25:01","2026-04-16 06:44:52",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F5b7e4c3c-a12e-4b11-9673-79a7060052a8?source=api-prod",1,[22,23,24,25,26,27],"README.txt","betterdocs.php","includes\u002FCore\u002FRequest.php","includes\u002FCore\u002FRewrite.php","includes\u002FPlugin.php","views\u002Fshortcodes\u002Ffeedback-form.php","researched",false,3,"# Vulnerability Analysis: CVE-2026-3875 - BetterDocs Stored XSS via Shortcode Attributes\n\n## 1. Vulnerability Summary\nThe **BetterDocs** plugin (\u003C= 4.3.8) is vulnerable to **Authenticated Stored Cross-Site Scripting (XSS)**. The flaw exists in the handling of the `betterdocs_feedback_form` shortcode. Specifically, several attributes used to define labels within the feedback form are rendered in the frontend template without undergoing proper sanitization (on input) or escaping (on output). This allows a user with **Contributor** level permissions or higher to embed malicious JavaScript within a post or page.\n\n## 2. Attack Vector Analysis\n*   **Shortcode:** `[betterdocs_feedback_form]`\n*   **Vulnerable Attributes (Inferred):** `name_label`, `email_label`, `message_label` (mapping to `$feedback_form_name_label_text`, etc. in the template).\n*   **Authentication Level:** Contributor+ (any role allowed to use shortcodes in posts).\n*   **Sink:** `views\u002Fshortcodes\u002Ffeedback-form.php` using raw `echo` statements for label variables.\n*   **Preconditions:** The plugin must be active. A Contributor user must be able to create or edit a post.\n\n## 3. Code Flow\n1.  **Registration:** `WPDeveloper\\BetterDocs\\Core\\ShortcodeFactory` (referenced in `includes\u002FPlugin.php`) registers the `betterdocs_feedback_form` shortcode.\n2.  **Processing:** When a post containing the shortcode is rendered, the shortcode callback extracts attributes from the `$atts` array.\n3.  **Variable Assignment:** The callback assigns attribute values (e.g., `name_label`) to local variables (e.g., `$feedback_form_name_label_text`).\n4.  **Template Loading:** The plugin loads the template file `views\u002Fshortcodes\u002Ffeedback-form.php`.\n5.  **The Sink:** Inside `views\u002Fshortcodes\u002Ffeedback-form.php`, the variables are output directly:\n    ```php\n    \u002F\u002F views\u002Fshortcodes\u002Ffeedback-form.php lines 6, 12, 18\n    \u003C?php echo $feedback_form_name_label_text; ?>\n    \u003C?php echo $feedback_form_email_label_text; ?>\n    \u003C?php echo $feedback_form_message_label_text; ?>\n    ```\n    Unlike `$button_text` (line 27) which uses `esc_attr()`, these labels are not escaped, leading to XSS.\n\n## 4. Nonce Acquisition Strategy\nFor this specific **Stored XSS via Shortcode**, a WordPress nonce is **not required** to trigger the vulnerability itself, as the exploitation happens during the standard post-creation process (Contributor) and the subsequent page rendering (Victim).\n\nHowever, if the agent needs to interact with the feedback form's AJAX submission (to test if the XSS can be triggered via form response), a nonce for the action `betterdocs_feedback_form_action` (or similar) might be needed.\n*   **Location:** Nonces are typically localized in `includes\u002FCore\u002FScripts.php`.\n*   **JS Variable:** Likely `window.betterdocs_settings?.nonce` or `window.betterdocs_feedback_form_params?.nonce`.\n*   **Acquisition:**\n    1.  Create a page with the shortcode: `wp post create --post_type=page --post_status=publish --post_content='[betterdocs_feedback_form]'`\n    2.  Navigate to the page: `browser_navigate(URL)`\n    3.  Extract via JS: `browser_eval(\"window.betterdocs_settings?.nonce\")`\n\n## 5. Exploitation Strategy\nThe goal is to inject a script that executes when an Administrator views the page.\n\n1.  **Login as Contributor:** Use the `http_request` tool to authenticate or use `wp-cli` to create a user and then authenticate.\n2.  **Inject Shortcode:** Create a new post containing the malicious shortcode.\n    *   **Payload:** `[betterdocs_feedback_form name_label='Name\u003Cscript>alert(document.domain)\u003C\u002Fscript>']`\n3.  **Submit for Review:** (Optional) As a Contributor, the post will be in `pending` status.\n4.  **Trigger (Admin Context):** Use the `browser_navigate` tool logged in as an **Administrator** to view the post (either the public URL if published or the preview\u002Fedit URL if pending).\n5.  **Payload Variations:**\n    *   Attribute breakout: `name_label='\">\u003Cscript>alert(1)\u003C\u002Fscript>'`\n    *   Template context injection: `message_label='\u003C\u002Flabel>\u003Cscript>alert(1)\u003C\u002Fscript>\u003Clabel>'`\n\n## 6. Test Data Setup\n1.  **Users:**\n    *   `admin_user` (Administrator)\n    *   `attacker_user` (Contributor)\n2.  **Target Content:**\n    *   A page or post created by `attacker_user` with the content:\n        `[betterdocs_feedback_form name_label='Name\u003Cimg src=x onerror=alert(\"XSS_NAME\")>' email_label='Email\u003Cimg src=x onerror=alert(\"XSS_EMAIL\")>' message_label='Msg\u003Cimg src=x onerror=alert(\"XSS_MSG\")>']`\n\n## 7. Expected Results\n*   When the Administrator navigates to the post containing the shortcode, the browser should execute the JavaScript contained in the `name_label`, `email_label`, or `message_label` attributes.\n*   The raw HTML source of the rendered page will show the payload unescaped within the `\u003Clabel>` tags of the `betterdocs-feedback-form`.\n\n## 8. Verification Steps\n1.  **Check Post Content:** `wp post get \u003CID> --field=post_content` to ensure the shortcode was saved correctly.\n2.  **Verify Frontend Output:**\n    *   Navigate to the post URL.\n    *   Inspect the HTML: Search for `form-name` or `form-email` classes.\n    *   Confirm the presence of: `\u003Clabel for=\"message_name\" class=\"form-name\">Name\u003Cimg src=x onerror=alert(\"XSS_NAME\")> ...`\n3.  **Confirm Execution:** Use `browser_eval` to check for a global variable set by the payload (e.g., `window.xss_executed = true`).\n\n## 9. Alternative Approaches\n*   **Attribute: `button_text`:** Although line 27 uses `esc_attr()`, check if it's vulnerable to attribute breakout if unquoted or if `esc_attr` is bypassed via double encoding (unlikely in this version).\n*   **Shortcode: `betterdocs_search_form`:** If the feedback form is patched or unavailable, other BetterDocs shortcodes often share similar logic for labels and placeholders.\n*   **DOM XSS:** Check `assets\u002Fjs\u002Fbetterdocs-feedback-form.js` (if it exists) to see if it handles the submission response by injecting it into `.response` (line 2 of the template) using `.innerHTML`. If so, the XSS could be triggered via the feedback submission response if the server-side handler is also unescaped.","The BetterDocs plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'betterdocs_feedback_form' shortcode attributes in versions up to 4.3.8. This allows authenticated attackers with Contributor-level permissions or higher to inject arbitrary JavaScript into a post or page, which executes in the context of any user viewing the page.","\u002F\u002F views\u002Fshortcodes\u002Ffeedback-form.php lines 6, 12, 18\n\u003Clabel for=\"message_name\" class=\"form-name\">\n    \u003C?php echo $feedback_form_name_label_text; ?> \u003Cspan>*\u003C\u002Fspan> \u003Cbr>\n    \u003Cinput type=\"text\" id=\"message_name\" name=\"message_name\" aria-label=\"\u003C?php echo esc_html( 'Name', 'betterdocs' ); ?>\" value=\"\u003C?php echo esc_html( $name ); ?>\" \u002F>\n\u003C\u002Flabel>\n---\n\u003Clabel for=\"message_email\" class=\"form-email\">\n    \u003C?php echo $feedback_form_email_label_text; ?> \u003Cspan>*\u003C\u002Fspan> \u003Cbr>\n    \u003Cinput type=\"text\" id=\"message_email\" name=\"message_email\" aria-label=\"\u003C?php echo esc_html( 'Email', 'betterdocs' ); ?>\" value=\"\u003C?php echo esc_html( $email ); ?>\" \u002F>\n\u003C\u002Flabel>\n---\n\u003Clabel for=\"message_text\" class=\"form-message\">\n    \u003C?php echo $feedback_form_message_label_text; ?> \u003Cspan>*\u003C\u002Fspan> \u003Cbr>\n    \u003Ctextarea type=\"text\" id=\"message_text\" aria-label=\"\u003C?php echo esc_html( 'Message', 'betterdocs' ); ?>\" name=\"message_text\">\u003C\u002Ftextarea>\n\u003C\u002Flabel>","--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fbetterdocs\u002F4.3.8\u002Fviews\u002Fshortcodes\u002Ffeedback-form.php\t2025-01-21 06:19:26.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fbetterdocs\u002F4.3.9\u002Fviews\u002Fshortcodes\u002Ffeedback-form.php\t2026-03-11 10:19:56.000000000 +0000\n@@ -3,19 +3,19 @@\n \t\u003Cform id=\"betterdocs-feedback-form\" class=\"betterdocs-feedback-form\" action=\"\" method=\"post\">\n \t\t\u003Cp>\n \t\t\t\u003Clabel for=\"message_name\" class=\"form-name\">\n-\t\t\t\t\u003C?php echo $feedback_form_name_label_text; ?> \u003Cspan>*\u003C\u002Fspan> \u003Cbr>\n-\t\t\t\t\u003Cinput type=\"text\" id=\"message_name\" name=\"message_name\" aria-label=\"\u003C?php echo esc_html( 'Name', 'betterdocs' ); ?>\" value=\"\u003C?php echo esc_html( $name ); ?>\" \u002F>\n+\t\t\t\t\u003C?php echo esc_html( $feedback_form_name_label_text ); ?> \u003Cspan>*\u003C\u002Fspan> \u003Cbr>\n+\t\t\t\t\u003Cinput type=\"text\" id=\"message_name\" name=\"message_name\" aria-label=\"\u003C?php echo esc_html( 'Name', 'betterdocs' ); ?>\" value=\"\u003C?php echo esc_attr( $name ); ?>\" \u002F>\n \t\t\t\u003C\u002Flabel>\n \t\t\u003C\u002Fp>\n \t\t\u003Cp>\n \t\t\t\u003Clabel for=\"message_email\" class=\"form-email\">\n-\t\t\t\t\u003C?php echo $feedback_form_email_label_text; ?> \u003Cspan>*\u003C\u002Fspan> \u003Cbr>\n-\t\t\t\t\u003Cinput type=\"text\" id=\"message_email\" name=\"message_email\" aria-label=\"\u003C?php echo esc_html( 'Email', 'betterdocs' ); ?>\" value=\"\u003C?php echo esc_html( $email ); ?>\" \u002F>\n+\t\t\t\t\u003C?php echo esc_html( $feedback_form_email_label_text ); ?> \u003Cspan>*\u003C\u002Fspan> \u003Cbr>\n+\t\t\t\t\u003Cinput type=\"text\" id=\"message_email\" name=\"message_email\" aria-label=\"\u003C?php echo esc_html( 'Email', 'betterdocs' ); ?>\" value=\"\u003C?php echo esc_attr( $email ); ?>\" \u002F>\n \t\t\t\u003C\u002Flabel>\n \t\t\u003C\u002Fp>\n \t\t\u003Cp>\n \t\t\t\u003Clabel for=\"message_text\" class=\"form-message\">\n-\t\t\t\t\u003C?php echo $feedback_form_message_label_text; ?> \u003Cspan>*\u003C\u002Fspan> \u003Cbr>\n+\t\t\t\t\u003C?php echo esc_html( $feedback_form_message_label_text ); ?> \u003Cspan>*\u003C\u002Fspan> \u003Cbr>\n \t\t\t\t\u003Ctextarea type=\"text\" id=\"message_text\" aria-label=\"\u003C?php echo esc_html( 'Message', 'betterdocs' ); ?>\" name=\"message_text\">\u003C\u002Ftextarea>\n \t\t\t\u003C\u002Flabel>\n \t\t\u003C\u002Fp>","1. Authenticate as a user with Contributor-level privileges or higher.\n2. Create a new post or edit an existing one.\n3. Embed the following shortcode into the post content: [betterdocs_feedback_form name_label=\"Name\u003Cscript>alert(document.domain)\u003C\u002Fscript>\"].\n4. Save the post (and submit for review if necessary).\n5. As a victim (e.g., an Administrator), navigate to the page where the post is rendered.\n6. The payload will execute because the `name_label` attribute is echoed directly into the HTML without sanitization or escaping.","gemini-3-flash-preview","2026-04-16 15:20:57","2026-04-16 15:21:26",{"type":40,"vulnerable_version":41,"fixed_version":11,"vulnerable_browse":42,"vulnerable_zip":43,"fixed_browse":44,"fixed_zip":45,"all_tags":46},"plugin","4.3.8","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fbetterdocs\u002Ftags\u002F4.3.8","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fbetterdocs.4.3.8.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fbetterdocs\u002Ftags\u002F4.3.9","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fbetterdocs.4.3.9.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fbetterdocs\u002Ftags"]