CVE-2026-23976

Modula Image Gallery <= 2.13.4 - Authenticated (Author+) Stored Cross-Site Scripting

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

Description

The Modula Image Gallery plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 2.13.4 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: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<=2.13.4
PublishedFebruary 4, 2026
Last updatedFebruary 9, 2026

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-23976 (Modula Image Gallery) ## 1. Vulnerability Summary The **Modula Image Gallery** plugin (<= 2.13.4) is vulnerable to **Authenticated Stored Cross-Site Scripting (XSS)**. The vulnerability exists because the plugin fails to sufficiently sanitize or escape …

Show full research plan

Exploitation Research Plan: CVE-2026-23976 (Modula Image Gallery)

1. Vulnerability Summary

The Modula Image Gallery plugin (<= 2.13.4) is vulnerable to Authenticated Stored Cross-Site Scripting (XSS). The vulnerability exists because the plugin fails to sufficiently sanitize or escape user-supplied input when saving and displaying gallery settings or image metadata. An attacker with Author level permissions or higher can inject malicious scripts into gallery fields. These scripts execute in the context of any user (including administrators) who visits the page where the gallery is embedded or views the gallery in the admin dashboard.

2. Attack Vector Analysis

  • Endpoint: wp-admin/admin-ajax.php
  • AJAX Action: modula_save_image_metadata (inferred) or via the standard post.php update mechanism for the modula-gallery custom post type.
  • Vulnerable Parameters: metadata[caption], metadata[title], metadata[alt], or custom link attributes (inferred).
  • Authentication: Requires an account with at least Author privileges (the ability to create and edit Modula galleries).
  • Preconditions: The plugin must be active, and at least one gallery must exist (or the attacker must be able to create one).

3. Code Flow (Inferred)

  1. Input: An Author user submits a request to update image metadata within a gallery.
  2. Handling: The plugin catches the request via an AJAX handler (likely in includes/class-modula-ajax.php) or the save_post hook for the modula-gallery post type.
  3. Storage: The input is saved to the database using update_post_meta() or update_option() without rigorous sanitization (e.g., using wp_kses with an insufficient allowlist).
  4. Rendering: When the gallery is rendered via the [modula id="..."] shortcode, the plugin retrieves the stored metadata.
  5. Output: The plugin echoes the metadata in the frontend HTML (e.g., in includes/class-modula-shortcode.php or gallery templates) without applying esc_html(), esc_attr(), or wp_kses().

4. Nonce Acquisition Strategy

Modula uses localized scripts to provide nonces and AJAX URLs to its admin interface.

  1. Identify Shortcode: The plugin uses [modula id="ID"].
  2. Create Test Content: Use WP-CLI to create a gallery and a page to host it.
  3. Navigate to Gallery Edit Page: As an Author, navigate to the "Edit Gallery" screen for a specific gallery (wp-admin/post.php?post=ID&action=edit).
  4. Extract Nonce:
    • The plugin localizes data under the object modula_vars or modula_admin_vars (inferred).
    • Use browser_eval to extract the nonce:
      browser_eval("window.modula_vars?.nonce || window.modula_admin_vars?.nonce")
    • Also, check for specific metadata nonces: window.modula_vars?.image_metadata_nonce.

5. Exploitation Strategy

Step 1: Authentication and Setup

  1. Log in as a user with the Author role.
  2. Identify an existing gallery ID or create a new one.

Step 2: Payload Injection

We will target the image metadata update AJAX action, as this is a common vector for stored XSS in gallery plugins.

Request:

  • Method: POST
  • URL: https://[target]/wp-admin/admin-ajax.php
  • Content-Type: application/x-www-form-urlencoded
  • Body:
    action=modula_save_image_metadata&
    nonce=[EXTRACTED_NONCE]&
    image_id=[ATTACHMENT_ID]&
    metadata[title]=Test Title&
    metadata[caption]=<img src=x onerror=alert(document.domain)>&
    metadata[alt]=Exploit
    

Step 3: Triggering the XSS

  1. Place the gallery shortcode [modula id="GALLERY_ID"] on a public page or post.
  2. Navigate to that page using browser_navigate.
  3. Observe the execution of alert(document.domain).

6. Test Data Setup

  1. Create Author User:
    wp user create attacker attacker@example.com --role=author --user_pass=password123
  2. Create a Modula Gallery:
    Modula stores galleries as modula-gallery post types.
    wp post create --post_type=modula-gallery --post_title="XSS Gallery" --post_status=publish --post_author=[ATTACKER_ID]
  3. Upload an Image:
    Upload an image to the media library to get an attachment_id.
  4. Attach Image to Gallery:
    Modula usually stores gallery items in post meta modula_images.
  5. Create Page with Shortcode:
    wp post create --post_type=page --post_title="Gallery Page" --post_content='[modula id="[GALLERY_ID]"]' --post_status=publish

7. Expected Results

  • The admin-ajax.php request should return a success response (likely JSON {"success": true}).
  • When viewing the "Gallery Page", the browser should execute the JavaScript injected into the caption field.
  • The HTML source of the page should show the unescaped payload: <div class="modula-item-caption">...<img src=x onerror=alert(document.domain)>...</div>.

8. Verification Steps

  1. Database Check:
    Check the post meta for the attachment to confirm the payload is stored:
    wp post meta get [ATTACHMENT_ID] _modula_image_metadata (inferred meta key)
    OR check the gallery post meta:
    wp post meta get [GALLERY_ID] modula_images
  2. Frontend Check:
    Verify the payload appears in the HTTP response body:
    http_request --url "https://[target]/gallery-page/"
    Search for onerror=alert.

9. Alternative Approaches

If the modula_save_image_metadata AJAX action is protected or incorrect:

  1. Direct Post Update: Attempt to update the modula-gallery post directly via post.php by including the malicious payload in the modula_settings or modula_tabs array parameters.
  2. Settings XSS: Look for gallery-wide settings like "Custom CSS" or "Custom JS" (often found in Modula) and attempt to inject a payload there.
  3. Bulk Edit: If the plugin has a bulk metadata editor, test the modula_bulk_edit_images action.

Check if your site is affected.

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