[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fTbwtwOO9NgaOun2aXWrkxTu16DUorKg2iHASbp2ETNc":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":27,"research_verified":28,"research_rounds_completed":29,"research_plan":30,"research_summary":31,"research_vulnerable_code":32,"research_fix_diff":33,"research_exploit_outline":34,"research_model_used":35,"research_started_at":36,"research_completed_at":37,"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":28,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":28,"source_links":38},"CVE-2026-11898","white-label-cms-authenticated-administrator-stored-cross-site-scripting-via-import-settings","White Label CMS \u003C= 2.7.12 - Authenticated (Administrator+) Stored Cross-Site Scripting via Import Settings","The White Label CMS plugin for WordPress is vulnerable to Stored Cross-Site Scripting via admin settings in all versions up to, and including, 2.7.12 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with administrator-level permissions 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.","white-label-cms",null,"\u003C=2.7.12","2.7.13","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-07-10 16:44:07","2026-07-11 05:35:45",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F1f12cdb6-df2d-419d-a29c-1ff7f9d098f4?source=api-prod",1,[22,23,24,25,26],"changelog.txt","includes\u002Fclasses\u002FAdmin_Dashboard.php","includes\u002Fclasses\u002FSettings.php","readme.txt","wlcms-plugin.php","researched",false,3,"# Exploitation Research Plan - CVE-2026-11898\n\n## 1. Vulnerability Summary\nThe **White Label CMS** plugin for WordPress (versions \u003C= 2.7.12) is vulnerable to **Stored Cross-Site Scripting (XSS)** via its \"Import Settings\" functionality. The vulnerability exists because the `WLCMS_Settings::import()` method directly decodes JSON input from an uploaded file and saves it to the WordPress options table using `update_option()` without any sanitization or validation of the setting values. While the standard settings save mechanism (`WLCMS_Settings::store()`) applies `wlcms_kses()` to inputs, the import mechanism bypasses this protection. This allows an Administrator (or Super Admin in Multisite) to inject arbitrary scripts that execute when the settings are rendered, particularly affecting environments where `unfiltered_html` is disabled.\n\n## 2. Attack Vector Analysis\n- **Endpoint:** `admin-init` hook via the plugin's settings page.\n- **Action:** Form submission to `options-general.php?page=wlcms-plugin.php`.\n- **Vulnerable Parameter:** `import_file` (file upload containing JSON).\n- **Required Authentication:** Administrator or Super Admin.\n- **Preconditions:**\n    - Plugin version \u003C= 2.7.12.\n    - Multisite installation OR a single-site installation where the `unfiltered_html` capability has been disabled for administrators (e.g., via a security plugin or `wp-config.php`).\n- **Target Setting:** The `dashboard_title` setting is an ideal target because it is rendered inside a JavaScript string via `wlcms_add_js()`, allowing for JS string breakout.\n\n## 3. Code Flow\n1.  **Entry Point:** `includes\u002Fclasses\u002FSettings.php`: `WLCMS_Settings::init()` is hooked to `admin_init`.\n2.  **Handler:** `init()` calls `$this->import()`.\n3.  **Authentication\u002FNonce Check:**\n    - `import()` checks `is_wlcms_super_admin()`.\n    - It verifies the nonce: `wp_verify_nonce($_POST['wlcms-settings_nonce'], 'wlcms-settings-action')`.\n4.  **File Processing:**\n    - It retrieves the uploaded file: `$temp_file_raw = $_FILES['import_file']['tmp_name']`.\n    - It reads and decodes the JSON: `$settings = (array)json_decode(file_get_contents($temp_file), true);`.\n5.  **Vulnerable Sink:**\n    - It calls `$this->setAll($settings)` and then `$this->save()`.\n    - `save()` executes `update_option(\"wlcms_options\", $this->settings)`. **No sanitization occurs here.**\n6.  **Rendering (XSS):**\n    - `includes\u002Fclasses\u002FAdmin_Dashboard.php`: `dashboard_title()` retrieves the setting: `$title = $this->get_settings('dashboard_title')`.\n    - It constructs a string: `$dashboard_title .= '\u003Cspan id=\\\"wlcms_dashboard_title\\\">' . esc_attr($title) . '\u003C\u002Fspan>';`.\n    - It injects this into an inline script: `wlcms_add_js('jQuery(\".index-php #wpbody-content .wrap h1:eq(0)\").html(\"' . $dashboard_title . '\")');`.\n\n## 4. Nonce Acquisition Strategy\nThe nonce `wlcms-settings_nonce` is generated in the `parts\u002Fimport-settings` view and rendered on the White Label CMS settings page.\n\n1.  **Navigate:** Use `browser_navigate` to `wp-admin\u002Foptions-general.php?page=wlcms-plugin.php`.\n2.  **Extract:** The nonce is stored in a hidden input field within the import form.\n3.  **JavaScript Extraction:**\n    ```javascript\n    \u002F\u002F Extract the nonce value from the form\n    document.querySelector('input[name=\"wlcms-settings_nonce\"]').value\n    ```\n\n## 5. Exploitation Strategy\nThe goal is to provide a JSON file that breaks out of the JavaScript string context in `dashboard_title()`.\n\n### Payload Preparation\nCreate a file named `exploit.json`:\n```json\n{\n  \"dashboard_title\": \"\\\");alert(document.domain);(\\\"\"\n}\n```\n*Note: When `esc_attr` processes this, it remains `\");alert(document.domain);(\"`. When placed into the `wlcms_add_js` call, it results in: `jQuery(...).html(\"\u003Cspan ...>\");alert(document.domain);(\"\u003C\u002Fspan>\")`.*\n\n### Step-by-Step Execution\n1.  **Login:** Authenticate as an Administrator.\n2.  **Get Nonce:** Navigate to `wp-admin\u002Foptions-general.php?page=wlcms-plugin.php` and extract the value of `wlcms-settings_nonce`.\n3.  **Upload Exploit:**\n    - Use `http_request` to send a `POST` request to `wp-admin\u002Foptions-general.php?page=wlcms-plugin.php`.\n    - **Content-Type:** `multipart\u002Fform-data`.\n    - **Parameters:**\n        - `wlcms-settings_nonce`: [EXTRACTED_NONCE]\n        - `import_file`: [exploit.json content]\n4.  **Trigger:** Navigate to the WordPress Dashboard (`wp-admin\u002Findex.php`).\n\n## 6. Test Data Setup\n1.  **Install Plugin:** `wp plugin install white-label-cms --version=2.7.12 --activate`.\n2.  **Disable unfiltered_html (Simulate restricted Admin):**\n    ```bash\n    wp eval \"role = get_role('administrator'); role->remove_cap('unfiltered_html');\"\n    ```\n3.  **User:** Ensure an administrator user exists.\n\n## 7. Expected Results\n- The `import()` function will process the JSON and update the `wlcms_options` option.\n- Upon visiting the Dashboard, the `dashboard_title()` function will generate a script block.\n- The browser will execute the injected JavaScript, resulting in an alert box displaying the document domain.\n\n## 8. Verification Steps\n1.  **Check Database:**\n    ```bash\n    wp option get wlcms_options --format=json | grep \"alert\"\n    ```\n2.  **Inspect Page Source:** Navigate to the Dashboard and search for the injected string in the HTML source. It will appear within a `\u003Cscript>` block managed by the plugin.\n\n## 9. Alternative Approaches\nIf the `dashboard_title` injection is mitigated by the way `wlcms_add_js` escapes quotes, target the **Custom RSS Feed** or **Custom Welcome Panel** settings.\n\n**RSS Feed Target:**\nInject the payload into the `rss_title` setting. If the plugin renders the RSS title on the dashboard using `echo` without `esc_html()`, a standard tag-based payload will work:\n```json\n{\n  \"rss_title\": \"\u003Cimg src=x onerror=alert(1)>\"\n}\n```\n\n**Welcome Panel Target:**\nSettings like `welcome_panel` often store HTML templates. Injecting a script tag directly into the panel content key might be successful if the output function assumes the content was already sanitized during the (bypassed) `store()` phase.","The White Label CMS plugin for WordPress is vulnerable to Stored Cross-Site Scripting (XSS) via its 'Import Settings' feature in versions up to and including 2.7.12. This vulnerability allows authenticated administrators to bypass standard input sanitization by uploading a malicious JSON configuration file, leading to the execution of arbitrary scripts when the affected settings are rendered on the dashboard.","\u002F\u002F includes\u002Fclasses\u002FSettings.php (approx. lines 215-226)\n        $settings = (array)json_decode(\n            file_get_contents($temp_file),\n            true\n        );\n\n        unlink($temp_file);\n\n        if (!$settings) {\n\n            WLCMS_Queue('Nothing to import, please check your json file format.', 'error');\n            wp_redirect(wlcms()->admin_url());\n            exit;\n        }\n\n        $this->setAll($settings);\n        $this->save();\n\n---\n\n\u002F\u002F includes\u002Fclasses\u002FAdmin_Dashboard.php (approx. lines 426-431)\n        $introduction = $this->get_settings('rss_introduction');\n        $url = $this->get_settings('rss_feed_address');\n\n        if ($introduction) {\n            echo '\u003Cp>' . $introduction . '\u003C\u002Fp>';\n        }","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwhite-label-cms\u002F2.7.12\u002Fincludes\u002Fclasses\u002FAdmin_Dashboard.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwhite-label-cms\u002F2.7.13\u002Fincludes\u002Fclasses\u002FAdmin_Dashboard.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwhite-label-cms\u002F2.7.12\u002Fincludes\u002Fclasses\u002FAdmin_Dashboard.php\t2025-04-30 01:02:50.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwhite-label-cms\u002F2.7.13\u002Fincludes\u002Fclasses\u002FAdmin_Dashboard.php\t2026-06-24 01:07:16.000000000 +0000\n@@ -427,13 +427,13 @@\n         $url = $this->get_settings('rss_feed_address');\n \n         if ($introduction) {\n-            echo '\u003Cp>' . $introduction . '\u003C\u002Fp>';\n+            echo '\u003Cp>' . wp_kses_post($introduction) . '\u003C\u002Fp>';\n         }\n \n         $rss = fetch_feed($url);\n \n         if ($error = is_wp_error($rss)) {\n-            echo '\u003Cdiv class=\"warning-text\">' . $rss->get_error_message() . '\u003C\u002Fdiv>';\n+            echo '\u003Cdiv class=\"warning-text\">' . esc_html($rss->get_error_message()) . '\u003C\u002Fdiv>';\n \n             wlcms_set_css(\n                 '.index-php .warning-text',\n@@ -462,7 +462,7 @@\n             );\n \n             if ($show_post_content) :\n-                $rss_list .= preg_replace('\u002F\u003Cimg[^>]+.\u002F', '', $item->get_content());\n+                $rss_list .= wp_kses_post($item->get_content());\n \n             endif;\n             $rss_list .= '\u003C\u002Fli>';\ndiff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwhite-label-cms\u002F2.7.12\u002Fincludes\u002Fclasses\u002FSettings.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwhite-label-cms\u002F2.7.13\u002Fincludes\u002Fclasses\u002FSettings.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwhite-label-cms\u002F2.7.12\u002Fincludes\u002Fclasses\u002FSettings.php\t2025-04-30 01:02:50.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fwhite-label-cms\u002F2.7.13\u002Fincludes\u002Fclasses\u002FSettings.php\t2026-06-24 01:07:16.000000000 +0000\n@@ -225,6 +225,15 @@\n             exit;\n         }\n \n+        \u002F\u002F Validate the JSON schema: only accept keys the plugin actually\n+        \u002F\u002F recognises so arbitrary options cannot be injected via import.\n+        $allowed_keys = array_merge($this->keys(), array('version'));\n+        $settings = array_intersect_key($settings, array_flip($allowed_keys));\n+\n+        \u002F\u002F Sanitize imported values the same way the regular save path does\n+        \u002F\u002F (see store()), so untrusted JSON cannot smuggle in unescaped markup.\n+        $settings = wlcms_kses($settings);\n+\n         $this->setAll($settings);\n         $this->save();","To exploit this vulnerability, an authenticated Administrator or Super Admin must first obtain a valid security nonce (`wlcms-settings_nonce`) from the plugin's settings page at `wp-admin\u002Foptions-general.php?page=wlcms-plugin.php`. The attacker then prepares a JSON file containing a payload where one or more setting keys (e.g., 'rss_introduction' or 'dashboard_title') are assigned malicious JavaScript or HTML. By submitting a POST request to the same settings page with the `multipart\u002Fform-data` content type, providing the extracted nonce, and uploading the JSON file via the `import_file` parameter, the malicious settings are saved to the database. The XSS payload executes when a user navigates to the WordPress Dashboard, where the plugin renders the affected settings.","gemini-3-flash-preview","2026-07-15 08:34:42","2026-07-15 08:35:36",{"type":39,"vulnerable_version":40,"fixed_version":11,"vulnerable_browse":41,"vulnerable_zip":42,"fixed_browse":43,"fixed_zip":44,"all_tags":45},"plugin","2.7.12","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwhite-label-cms\u002Ftags\u002F2.7.12","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fwhite-label-cms.2.7.12.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwhite-label-cms\u002Ftags\u002F2.7.13","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fwhite-label-cms.2.7.13.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fwhite-label-cms\u002Ftags"]