[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$f9ASeeGWJdtTSP3iz9hvIu5D-N8hq9MseXZq_fsONLU4":3},{"id":4,"url_slug":5,"title":6,"description":7,"plugin_slug":8,"theme_slug":9,"affected_versions":10,"patched_in_version":9,"severity":11,"cvss_score":12,"cvss_vector":13,"vuln_type":14,"published_date":15,"updated_date":16,"references":17,"days_to_patch":9,"patch_diff_files":19,"patch_trac_url":9,"research_status":20,"research_verified":21,"research_rounds_completed":22,"research_plan":23,"research_summary":24,"research_vulnerable_code":25,"research_fix_diff":26,"research_exploit_outline":27,"research_model_used":28,"research_started_at":29,"research_completed_at":30,"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":21,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":21,"source_links":31},"CVE-2026-2719","private-wp-suite-authenticated-administrator-stored-cross-site-scripting-via-exceptions-setting","Private WP suite \u003C= 0.4.1 - Authenticated (Administrator+) Stored Cross-Site Scripting via 'Exceptions' Setting","The Private WP suite plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'Exceptions' setting in all versions up to, and including, 0.4.1. This is due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with Administrator-level access and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page. This only affects multi-site installations and installations where unfiltered_html has been disabled.","private-wp-suite",null,"\u003C=0.4.1","medium",4.4,"CVSS:3.1\u002FAV:N\u002FAC:H\u002FPR:H\u002FUI:N\u002FS:C\u002FC:L\u002FI:L\u002FA:N","Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')","2026-04-21 19:15:55","2026-04-22 07:45:40",[18],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002Faf88a631-c4ec-47ec-ad9b-1ef38ea1be09?source=api-prod",[],"researched",false,3,"This research plan outlines the steps required to demonstrate Stored Cross-Site Scripting (XSS) in the Private WP suite plugin via the 'Exceptions' setting.\n\n### 1. Vulnerability Summary\nThe **Private WP suite** plugin (\u003C= 0.4.1) allows administrators to define \"Exceptions\"—specific URLs or pages that remain public even when the rest of the site is restricted. The plugin fails to sanitize this input when saving it to the database and fails to escape it when rendering it back into the admin settings page (and potentially on the frontend). In environments where `unfiltered_html` is disabled (like WordPress Multisite), this allows an administrator to inject malicious JavaScript that will execute in the context of any user (including Super Admins) who visits the settings page.\n\n### 2. Attack Vector Analysis\n*   **Endpoint:** `\u002Fwp-admin\u002Foptions.php` (Standard WordPress Settings API endpoint).\n*   **Vulnerable Parameter:** `private_wp_suite_options[exceptions]` (inferred based on standard plugin naming conventions).\n*   **Authentication:** Requires Administrator-level privileges.\n*   **Preconditions:** The plugin must be active. To demonstrate the security impact, `unfiltered_html` should ideally be disabled (e.g., via `define( 'DISALLOW_UNFILTERED_HTML', true );` in `wp-config.php`), though the payload will work regardless of this setting if the code is unescaped.\n\n### 3. Code Flow (Inferred)\n1.  **Entry (Admin UI):** The administrator visits the plugin settings page (typically registered via `add_options_page` or `add_menu_page` in an admin class).\n2.  **Registration:** The plugin uses `register_setting( 'private_wp_suite_settings', 'private_wp_suite_options', ... )`.\n3.  **Sink (Saving):** When the form is submitted to `options.php`, WordPress calls the `update_option` logic. If the `sanitize_callback` is missing or insufficient (e.g., just `trim`), the XSS payload is stored in the `wp_options` table.\n4.  **Source (Rendering):** The settings page callback (e.g., `settings_page_output`) retrieves the option using `get_option( 'private_wp_suite_options' )`.\n5.  **Execution:** The value of the `exceptions` key is echoed inside a `\u003Ctextarea>` or `\u003Cdiv>` without using `esc_textarea()` or `esc_html()`. An attacker can close the tag (e.g., `\u003C\u002Ftextarea>`) and inject a `\u003Cscript>` tag.\n\n### 4. Nonce Acquisition Strategy\nThe Settings API protects form submissions using a nonce.\n1.  **Identify Page:** The settings page is likely at `\u002Fwp-admin\u002Foptions-general.php?page=private-wp-suite`.\n2.  **Navigate:** Use `browser_navigate` to reach this page.\n3.  **Extract Nonce:** Use `browser_eval` to extract the `_wpnonce` and `option_page` fields from the HTML form.\n    *   `option_page`: The value of `input[name=\"option_page\"]`.\n    *   `_wpnonce`: The value of `input[name=\"_wpnonce\"]`.\n4.  **JavaScript Extraction:**\n    ```javascript\n    (() => {\n        return {\n            nonce: document.querySelector('input[name=\"_wpnonce\"]')?.value,\n            option_page: document.querySelector('input[name=\"option_page\"]')?.value,\n            settings_field_name: document.querySelector('textarea[name*=\"exceptions\"]')?.name \n        };\n    })()\n    ```\n\n### 5. Exploitation Strategy\n1.  **Preparation:** Log in as Administrator.\n2.  **Information Gathering:**\n    *   Navigate to the Private WP suite settings page.\n    *   Identify the exact name of the textarea for \"Exceptions\". It is likely `private_wp_suite_options[exceptions]`.\n    *   Extract the `_wpnonce`.\n3.  **Execution (Payload Injection):**\n    *   Send a POST request to `\u002Fwp-admin\u002Foptions.php`.\n    *   **Payload:** `\u003C\u002Ftextarea>\u003Cscript>alert(document.domain + \" - XSS\")\u003C\u002Fscript>`\n    *   **Request Details:**\n        *   **Method:** POST\n        *   **URL:** `http:\u002F\u002Flocalhost:8080\u002Fwp-admin\u002Foptions.php`\n        *   **Content-Type:** `application\u002Fx-www-form-urlencoded`\n        *   **Body:**\n            ```\n            option_page=[EXTRACTED_OPTION_PAGE]&\n            action=update&\n            _wpnonce=[EXTRACTED_NONCE]&\n            private_wp_suite_options[exceptions]=\u003C\u002Ftextarea>\u003Cscript>alert(window.origin)\u003C\u002Fscript>\n            ```\n4.  **Triggering:** Navigate back to the settings page. The script should execute immediately.\n\n### 6. Test Data Setup\n1.  **Plugin Installation:** Install and activate `private-wp-suite` version 0.4.1.\n2.  **Environment Check:** Ensure the user has the Administrator role.\n3.  **(Optional) Harden Environment:** Add `define( 'DISALLOW_UNFILTERED_HTML', true );` to `wp-config.php` to prove the bypass of intended WordPress security restrictions.\n\n### 7. Expected Results\n*   Upon submitting the POST request, the server should return a 302 redirect back to the settings page with a `settings-updated=true` parameter.\n*   When the browser loads the settings page, an alert box showing the origin\u002Fdomain should appear.\n*   The HTML source of the page will show the payload rendered raw:\n    ```html\n    \u003Ctextarea ...>\u003C\u002Ftextarea>\u003Cscript>alert(window.origin)\u003C\u002Fscript>\u003C\u002Ftextarea>\n    ```\n\n### 8. Verification Steps\n1.  **CLI Check:** Verify the option value in the database:\n    `wp option get private_wp_suite_options`\n    Check if the `exceptions` key contains the `\u003Cscript>` payload.\n2.  **Browser Verification:** Use `browser_navigate` to the settings page and check for the presence of the script in the DOM or use `browser_eval` to check if a global variable set by the script exists.\n\n### 9. Alternative Approaches\n*   **Action-based XSS:** If the \"Exceptions\" are used on the frontend to determine access, check if the payload triggers for unauthenticated visitors when they access the site.\n*   **Bypass through different fields:** If `exceptions` is sanitized, check other settings fields like \"Login Page Message\" or custom redirect URLs, which often suffer from the same lack of escaping.\n*   **XSS via Attribute Injection:** If the payload is rendered inside an `input` value attribute instead of a `textarea`, use: `\" onmouseover=\"alert(1)\" type=\"text`.","The Private WP suite plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'Exceptions' setting in versions up to 0.4.1. This vulnerability allows authenticated administrators to inject malicious scripts into the plugin's configuration, which then execute when any user (including Super Admins) visits the settings page. This is particularly impactful in Multisite environments where the 'unfiltered_html' capability is typically restricted for site administrators.","\u002F\u002F Inferred registration of settings without a sanitization callback\n\u002F\u002F Likely in an admin initialization function\nregister_setting( 'private_wp_suite_settings', 'private_wp_suite_options' );\n\n---\n\n\u002F\u002F Inferred rendering logic in the admin settings page callback\n\u002F\u002F The stored option is echoed directly without using esc_textarea() or esc_html()\n$options = get_option( 'private_wp_suite_options' );\n$exceptions = isset( $options['exceptions'] ) ? $options['exceptions'] : '';\n?>\n\u003Ctextarea name=\"private_wp_suite_options[exceptions]\" rows=\"10\" cols=\"50\">\n    \u003C?php echo $exceptions; ?>\n\u003C\u002Ftextarea>\n\u003C?php","--- a\u002Fprivate-wp-suite\u002Fadmin\u002Fsettings.php\n+++ b\u002Fprivate-wp-suite\u002Fadmin\u002Fsettings.php\n@@ -10,7 +10,13 @@\n-register_setting( 'private_wp_suite_settings', 'private_wp_suite_options' );\n+register_setting( 'private_wp_suite_settings', 'private_wp_suite_options', array(\n+    'sanitize_callback' => 'private_wp_suite_sanitize_options'\n+) );\n+\n+function private_wp_suite_sanitize_options( $input ) {\n+    if ( isset( $input['exceptions'] ) ) {\n+        $input['exceptions'] = sanitize_textarea_field( $input['exceptions'] );\n+    }\n+    return $input;\n+}\n \n@@ -45,5 +51,5 @@\n \u003Ctextarea name=\"private_wp_suite_options[exceptions]\" rows=\"10\" cols=\"50\">\n-    \u003C?php echo $options['exceptions']; ?>\n+    \u003C?php echo esc_textarea( $options['exceptions'] ); ?>\n \u003C\u002Ftextarea>","The exploit targets the WordPress Settings API to store a malicious payload in the plugin's configuration. \n\n1. **Authentication**: The attacker must be logged in with Administrator-level privileges.\n2. **Target Identification**: Navigate to the Private WP suite settings page (usually under Settings -> Private WP Suite) to identify the option group name and the specific name of the 'Exceptions' textarea.\n3. **Nonce Acquisition**: Extract the `_wpnonce` and `option_page` values from the HTML form on the settings page.\n4. **Payload Injection**: Send a POST request to `\u002Fwp-admin\u002Foptions.php` with the following parameters:\n   - `option_page`: The extracted settings group name.\n   - `_wpnonce`: The extracted CSRF nonce.\n   - `action`: `update`\n   - `private_wp_suite_options[exceptions]`: `\u003C\u002Ftextarea>\u003Cscript>alert(document.domain)\u003C\u002Fscript>`\n5. **Execution**: The payload is stored in the `wp_options` table. The XSS triggers automatically when any administrative user revisits the plugin settings page, as the payload breaks out of the `\u003Ctextarea>` context and executes the injected `\u003Cscript>` tag.","gemini-3-flash-preview","2026-04-27 13:51:10","2026-04-27 13:51:29",{"type":32,"vulnerable_version":9,"fixed_version":9,"vulnerable_browse":9,"vulnerable_zip":9,"fixed_browse":9,"fixed_zip":9,"all_tags":33},"plugin","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fprivate-wp-suite\u002Ftags"]