Pingverablog ← Blog
Home › Blog › Orders Marked as Paid Without Payment: Check Your Payment Webhooks Before Black

Orders Marked as Paid Without Payment: Check Your Payment Webhooks Before Black Friday

October 20, 2026 · 12 min read

Orders Marked as Paid Without Payment: Check Your Payment Webhooks Before Black Friday

If your store has orders marked as paid without payment, the usual cause is a payment notification your store accepted without checking where it came from. A payment gateway reports a successful charge by calling a URL on your site (a webhook, IPN or callback). If the plugin behind that URL does not verify a signature or secret, anyone who can send an HTTP request can tell your store that an order was paid. The order moves to Processing, stock is reserved and the warehouse ships it.

The fix takes an afternoon. List every payment plugin, update the ones with known flaws, confirm that each webhook has a signing secret configured, and compare paid orders against the gateway's own record of captured payments. Between 11 September and 14 October 2026, public CVE records described at least six WooCommerce payment plugins with this kind of flaw. With Black Friday on 27 November 2026, the time to check is now, while your release calendar still allows plugin updates.

At a glance

  • A forged or unverified payment notification can move an unpaid order to a paid status. The order looks normal in the admin, and nothing appears in the gateway dashboard.
  • Public CVE records from September and October 2026 describe this flaw in WooCommerce plugins for Paymob, PayPay, Rede Itau, Asaas, Paymentfor and Walletdoc. A separate record covers a Stripe plugin that accepts unsigned events until a signing secret is saved.
  • Stripe signs every webhook with a per-endpoint secret starting with whsec_ and tells developers to verify the Stripe-Signature header. PayPal offers two verification methods and states that without one "you will not have a way to validate that its sender was in fact PayPal."
  • The safeguard that catches this whatever the plugin does is reconciliation: every order in a paid status should match a captured payment in the gateway, with the same amount and currency.
  • Gateways retry failed deliveries for days (Stripe up to three days in live mode, PayPal up to 25 times over three days), so your handler must also ignore duplicates.

Why it matters now

The CVE records published in the last six weeks describe the same flaw in several plugins:

  • Paymob for WooCommerce before 4.1.14 "does not verify the request signature on one branch" of its payment webhook, which lets unauthenticated attackers mark arbitrary orders as paid (CVE-2026-87978, published 23 September 2026, fixed in 4.1.14).
  • Payment Gateway PayPay for WooCommerce, versions 0.5 to 0.9.3, does not verify the authenticity of payment notifications. An attacker who knows the merchant identifier can mark orders paid, cancelled or failed (CVE-2026-82215, published 11 September 2026; the record lists no fixed version).
  • Rede Itau for WooCommerce before 5.4.7 does not verify its PIX payment webhook before moving a pending order to paid (CVE-2026-92430, published 19 September 2026).
  • Asaas Gateway for WooCommerce before 2.7.8 accepts an empty access token by default and does not check that the payment matches the order (CVE-2026-87974, published 14 October 2026).
  • Paymentfor Gateway for WooCommerce before 1.0.6 (CVE-2026-94360) and Walletdoc Payment Gateway for WooCommerce before 1.8.5 (CVE-2026-103307, which also includes an SQL injection) were both published on 14 October 2026.
  • Payment Gateway of Stripe for WooCommerce, up to and including 5.0.8, accepts unsigned webhook events when no signing secret is configured, which is the state after a fresh install. Once you save a valid secret, the plugin rejects forged requests (CVE-2026-9832, disclosed September 2026).

Most of these records carry a Medium CVSS score, because the attack changes order data without exposing it. For a store, the business impact can be bigger than the score suggests: goods leave the warehouse with no money behind them. As of October 2026 we have not seen a public report of mass exploitation of these specific CVEs, and we are not claiming one. The pattern is easy to exploit, though, and peak season puts the most goods in the shipping queue.

Your main gateway may also be safe while a second plugin is not. Many stores run a regional wallet, a buy-now-pay-later option or an older PayPal plugin that was added for one campaign and never removed. The flaw sits in whichever plugin owns the callback URL.

Step-by-step: audit your payment notifications this week

  1. List every payment method. In WooCommerce, go to Settings, then Payments, and write down each enabled method, the plugin that provides it, and its version. Then check the Plugins screen for payment plugins that are installed but disabled. A deactivated plugin cannot receive callbacks, but an inactive one you forgot about can be reactivated during a later fix, so remove it.
  2. Match each plugin against the CVE list above and against your vulnerability scanner or the plugin's changelog. Our WordPress version checker guide shows how to collect versions across several sites quickly.
  3. Update plugins that have a fixed release. Do this on staging first, run a real low-value test payment, then update production. If no fix exists (as with the PayPay record), disable that method until one ships, or place its orders on hold for manual review.
  4. Confirm the signing secret. For Stripe, the WooCommerce Stripe extension sets up webhooks automatically since version 8.6.1. Check that WooCommerce, Settings, Payments, Stripe, Settings, Account details, Configure connection shows the webhook as "Configured" on both the Live and Test tabs. For third-party Stripe plugins, paste the whsec_ secret from the Stripe Dashboard into the plugin settings and save. For other gateways, find the field called secret, token, signature key or similar. An empty field is a finding.
  5. Remove old endpoints in the gateway dashboard. Old webhook URLs that point to a staging site or a removed plugin add noise and can confuse reconciliation. The WooCommerce Stripe extension's "Reconfigure webhooks" option removes old webhooks that point to your site.
  6. Run the forged-notification test from the test plan below on staging. A correct handler rejects an unsigned request and leaves the order unchanged.
  7. Reconcile the last 30 days. Export orders in Processing and Completed status, export captured payments from each gateway, and match them on order number, amount and currency. Our payment-to-order reconciliation guide explains the matching rules in detail.
  8. Add a daily reconciliation check through peak, with a named owner and a rule for what happens to unmatched orders: they go On hold, and nobody ships them until someone has checked them.

Risk, owner and check

Risk Owner Check Frequency
Payment plugin with a known "mark as paid" flaw Developer or agency Compare installed versions with CVE records and changelogs Weekly until peak ends, then monthly
Webhook secret empty after reinstall or migration Developer Open each gateway's settings and confirm the secret field is set After every plugin install, migration or restore
Paid order with no captured payment Store operations Match paid orders to gateway captures on ID, amount and currency Daily from November to the end of January
Amount mismatch (paid in full, captured partly) Finance Same match, flag any difference Daily during peak
Duplicate notifications processed twice Developer Confirm the handler stores processed event IDs On each gateway plugin update
Unused payment plugin still installed Agency or site owner Remove plugins that are not enabled in Payments Quarterly

Copyable test plan: forged payment notification

Run this on staging or on a store you own and are authorised to test. Never send test requests to someone else's site.

PAYMENT WEBHOOK VERIFICATION TEST
Store: ____________   Environment: staging   Date: ________   Tester: ________

Preparation
[ ] Staging uses gateway test keys, not live keys
[ ] Gateway test-mode webhook points at the staging URL
[ ] Note the callback URL for each method
    (WooCommerce Stripe extension: https://staging.example.com/?wc-api=wc_stripe)

Test 1: unsigned request
[ ] Create order A with that method; leave it in Pending payment
[ ] Send a POST to the callback URL with a body that claims order A was paid,
    without a signature header (or with an obviously wrong one)
[ ] Expected: HTTP 4xx response, order A stays Pending payment,
    no "payment complete" note in the order
[ ] Result: ____________

Test 2: valid test payment
[ ] Pay order B with a gateway test card or sandbox account
[ ] Expected: order B moves to Processing, the order note shows the gateway
    transaction ID, the gateway dashboard shows the same amount and currency
[ ] Result: ____________

Test 3: duplicate delivery
[ ] Resend the order B event from the gateway dashboard
[ ] Expected: no second status change, no second confirmation email,
    no second stock reduction
[ ] Result: ____________

Test 4: amount mismatch (only if the plugin documents this check)
[ ] Confirm that a paid amount lower than the order total does not complete the order
[ ] Result: ____________

Sign-off: all four pass, or failures logged with owner and fix date: ________

A minimal unsigned request for Test 1 looks like this. Adjust the body to the format your gateway sends; the point is the missing signature.

curl -i -X POST "https://staging.example.com/?wc-api=wc_stripe" \
  -H "Content-Type: application/json" \
  -d '{"type":"payment_intent.succeeded","data":{"object":{"metadata":{"order_id":"1234"}}}}'

If the order changes status after this request, stop and treat the plugin as vulnerable until it is fixed.

Worked scenario (illustrative)

A store selling outdoor gear runs WooCommerce with the official Stripe extension and a regional wallet plugin added two years ago for one market. On a Monday in November, the daily reconciliation shows 214 paid orders in WooCommerce and 211 captures in Stripe plus the wallet provider combined. All three unmatched orders used the wallet method. Each has a "payment complete" note but no transaction ID that the provider can find, and two of them are for the most expensive tent in the catalogue, shipped to the same city.

The operations lead moves all three to On hold before the afternoon pick. The agency checks the wallet plugin version, finds it two releases behind a fix for webhook verification, updates it on staging, runs the test plan, and updates production the same day. The store disables the wallet method for the 24 hours that takes. With daily reconciliation in place, the store found the problem before shipping. Without it, the gap would have surfaced only at month-end close, after the parcels had left.

The numbers and the store are invented to show the procedure.

Common mistakes

  • Checking the main gateway and forgetting the others. The CVEs above are mostly in regional and secondary gateway plugins.
  • Assuming a configured gateway means a configured secret. Several of the records describe plugins whose secret or token is empty by default, so a store can take real payments for months with verification switched off.
  • Shipping on order status alone. During peak, "Processing" should mean "payment confirmed in the gateway", and you need a check that proves it.
  • Treating a failed delivery alert as noise. If the gateway reports failing webhooks, real payments may not be reaching your store, which shows up as paid customers with Pending orders. Our article on WooCommerce failed orders covers that side.
  • Restoring a backup or migrating hosts without re-checking webhook settings. Secrets live in the database or in the gateway dashboard, and either side can drift.

Limitations: this audit lowers the chance that a forged notification ships goods, but it does not make a store secure. It does not cover card testing (see our card testing attack guide), stolen admin accounts, or flaws in custom code. CVE records can be incomplete, and version numbers sometimes differ between databases, so confirm fixed versions in the plugin's own changelog.

FAQ

How do I confirm that a paid order was paid?

Look up the transaction ID from the order notes in the gateway dashboard. A real payment shows there as captured, with the same amount and currency. If you cannot find it, put the order on hold and do not ship it.

Does the official WooCommerce Stripe extension need a manual webhook secret?

According to WooCommerce documentation, since version 8.6.1 the extension sets up webhooks automatically when you connect Stripe. You should still confirm that the webhook shows as "Configured" on the Live and Test tabs. CVE-2026-9832 concerns a different, third-party Stripe plugin, where you save the secret yourself.

Should I freeze plugin updates before Black Friday?

Freeze feature changes, but still apply security fixes for payment plugins, tested on staging. Our Black Friday code freeze guide explains how to separate the two.

Sources

  • CVE-2026-87978, Paymob for WooCommerce: https://app.opencve.io/cve/CVE-2026-87978
  • CVE-2026-82215, Payment Gateway PayPay for WooCommerce: https://app.opencve.io/cve/CVE-2026-82215
  • CVE-2026-92430, Rede Itau for WooCommerce: https://app.opencve.io/cve/CVE-2026-92430
  • CVE-2026-87974, Asaas Gateway for WooCommerce: https://app.opencve.io/cve/CVE-2026-87974
  • CVE-2026-9832, Payment Gateway of Stripe for WooCommerce: https://stack.watch/vuln/CVE-2026-9832/
  • CVE-2026-94360, Paymentfor Gateway for WooCommerce: https://www.thehackerwire.com/vulnerability/CVE-2026-94360/
  • CVE-2026-103307, Walletdoc Payment Gateway for WooCommerce: https://www.thehackerwire.com/vulnerability/CVE-2026-103307/
  • Stripe, Receive Stripe events in your webhook endpoint: https://docs.stripe.com/webhooks
  • Stripe, Manage webhook endpoints: https://docs.stripe.com/webhooks/signature
  • PayPal Developer, Webhooks: https://developer.paypal.com/api/rest/webhooks/
  • WooCommerce, Stripe webhooks: https://woocommerce.com/document/stripe/setup-and-configuration/stripe-webhooks/

Last reviewed: 2026-10-20


Reconciliation catches a forged payment after the fact. If you also want to see order flow as it happens, Pingvera's WordPress connector sends WooCommerce order events (order created, order failed) to a unified timeline alongside deploys and incidents, so a plugin update and a change in order flow appear side by side. Its anomaly detector alerts when orders drop below the hourly baseline while the site is up. It does not verify payments, so keep the daily reconciliation in place.

Know about problems before your customers do

Pingvera watches whether an online business actually works — uptime, checkout, orders, domain, SSL and server — and alerts you in Telegram, email or a webhook before a customer has to tell you.

Start free

Read next: Local Payment Method Coverage for Ecommerce · Paid Campaign Landing Page QA Checklist · Pingvera Webhook to Help Desk Integration · Marketing Attribution Without Self-Deception · Run a free site check.

← All articles · Privacy policy · pingvera.com