CVE-2025-15386

Responsive Lightbox & Gallery < 2.6.1 - Unauthenticated Stored Cross-Site Scripting

highImproper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
7.2
CVSS Score
7.2
CVSS Score
high
Severity
2.6.1
Patched in
91d
Time to patch

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:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Changed
Low
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<2.6.1
PublishedFebruary 3, 2026
Last updatedMay 4, 2026
Affected pluginresponsive-lightbox

Source Code

WordPress.org SVN
Research Plan
Unverified

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…

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:

  1. Authorization: It does not check current_user_can() to verify the requester's identity.
  2. 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_field or wp_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_query or rl_get_pagination_html (inferred from plugin architecture).
  • Vulnerable Parameter: shortcode or args (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)

  1. Registration: The plugin registers a nopriv AJAX action:
    add_action( 'wp_ajax_nopriv_rl_remote_library_query', [ $this, 'remote_library_query' ] );
  2. Handler: The remote_library_query function (likely in includes/class-remote-library.php) is called.
  3. Processing: The function reads $_POST['shortcode'].
  4. Storage: The function uses update_post_meta($id, '_rl_cache', $_POST['shortcode']) or set_transient() to store the raw payload.
  5. 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.

  1. Identify Shortcode: The plugin's scripts are typically enqueued when the [responsive_lightbox_gallery] shortcode is present.
  2. Create Trigger Page: Create a public page containing the shortcode to ensure the frontend scripts load.
  3. Variable Name: The plugin uses the localization key rlArgs or responsive_lightbox_params (inferred).
  4. Nonce Key: The nonce is likely stored under nonce or rl_remote_library_nonce.

Execution Step:

// To be executed via browser_eval
window.rlArgs?.nonce || window.responsive_lightbox_params?.nonce

5. Exploitation Strategy

  1. Step 1: Setup Content: Create a page with the gallery shortcode to extract the nonce.
  2. Step 2: Nonce Extraction: Navigate to the page and use browser_eval to grab the nonce.
  3. Step 3: Inject Payload: Send a POST request to admin-ajax.php with 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")>
  4. 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

  1. Plugin Activation: Ensure responsive-lightbox is installed and active.
  2. Create Victim Page:
    wp post create --post_type=page --post_title="Gallery Page" --post_status=publish --post_content='[responsive_lightbox_gallery]'
    
  3. 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_SUCCESS should appear.
  • The database should show the unsanitized payload in the wp_postmeta or wp_options table.

8. Verification Steps

  1. Check Database:
    wp db query "SELECT meta_value FROM wp_postmeta WHERE meta_value LIKE '%onerror=alert%';"
    
  2. Verify Frontend Render: Use browser_navigate to the victim page and check if the alert is 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_query is 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).
Research Findings
Static analysis — not yet PoC-verified

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

--- includes/class-remote-library.php
+++ includes/class-remote-library.php
@@ -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.