Hundreds of small failed orders keep appearing
You open the orders page and it is full of orders you don't recognize. Most are failed or stuck in pending payment. They are small, often a single cheap product. The names look random, the emails are junk or belong to free mail services, and the billing addresses don't match the cards. They come in bursts, sometimes dozens in a few minutes, often at night in your time zone.
Your Stripe or other gateway dashboard shows a wall of declines with reasons like "incorrect CVC", "insufficient funds" or "card declined". New guest customers and accounts pile up. Then the email arrives from your processor about unusual activity or a high decline rate.
This is card testing. Someone is using your checkout to find out which stolen cards still work.
Why it happens
Stolen card details are sold in bulk, and many of the cards in a list are already dead. Before the buyer uses them for something valuable, they check them. The cheapest way to check a card is a small real payment attempt on a store that won't notice. A success means the card is live. A decline costs the attacker nothing.
WooCommerce stores get picked because:
- The checkout accepts unlimited attempts. By default, nothing stops one visitor from submitting the checkout hundreds of times.
- There are several ways in. The classic checkout form posts to
?wc-ajax=checkout. Block-based checkouts use the Store API at /wp-json/wc/store/v1/checkout. Scripts can call these directly without ever loading a page, so protection on the visible form alone does not cover them.
- Guest checkout means no friction. No account and no history are needed.
- Cheap products make good tests. A low-priced item keeps the test small.
- Usernames are public. WordPress exposes usernames at
/wp-json/wp/v2/users and through ?author=1 URLs unless you block them, which helps attackers target accounts.
None of this means your store is badly built. It means the defaults assume good faith.
What fixing it involves
I work in this order. The first two steps stop an active attack; the rest keeps it stopped.
1. Stop the bleeding at the edge
If the store is behind Cloudflare, I add rules before traffic ever reaches WordPress:
- A rate limiting rule on POST requests to the checkout paths above, including
/wp-json/wc/store/v1/checkout. A real customer submits checkout once or twice. A tester submits it over and over.
- A WAF custom rule that shows a Managed Challenge to checkout requests that look automated: no session cookie from earlier browsing, odd user agents, or countries you don't ship to. On plans with Bot Management, bot score is the strongest signal here.
- IP and ASN blocks for the worst sources, as a supplement.
The point is to block by behavior, not only by address. Testers rotate IPs constantly, so an IP list alone loses.
Without Cloudflare, a security plugin or your host's firewall can rate-limit those endpoints. WooCommerce also has built-in rate limiting for the Store API, but it is off by default and is switched on in code with the woocommerce_store_api_rate_limit_options filter. Some payment plugins add their own card-testing protection, such as a CAPTCHA on checkout; check what yours offers and turn it on.
2. Force card authentication
3D Secure asks the cardholder's bank to confirm the payment, usually through the banking app. A tester with a stolen card number can't pass it. With Stripe, Radar rules can request 3D Secure for risky payments. During an attack I set it to request it for every card that supports it, then relax it once things calm down. Which rules you can write depends on your Stripe plan, so check what your account allows. Other gateways have their own versions of this setting.
3D Secure adds a step for real buyers, so it is a lever to pull hard during an attack and ease off after.
3. Tighten the processor's fraud rules
In Stripe Radar, or your gateway's equivalent, I review the default rules and add blocks where the account allows: too many attempts from one IP or one email, CVC or postal code failures, and billing countries you don't serve. The processor sees patterns across many stores that you can't, so its fraud tools are worth using fully.
4. Block user enumeration
I close /wp-json/wp/v2/users to logged-out visitors and stop ?author= URLs from revealing usernames. This is not what stops card testing, but it removes an easy map of your accounts, and attackers who find one weak spot often probe for others.
5. Clean up the fake orders without emailing anyone
Filter the orders by status, date range and pattern, then bulk-cancel or trash them. Before you do, check WooCommerce, Settings, Emails. The "Cancelled order" and "Failed order" emails go to the admin by default, so pause those or expect a flood. Don't change these orders to Refunded or Completed, because those statuses can email the customer. Sending to fake addresses produces bounces, and bounces hurt your sending reputation for real customers.
Then remove the junk customer accounts the attack created. Look for accounts with no completed orders, registered in the attack window, with matching patterns in name or email.
If any test payment actually succeeded, refund it so the real cardholder doesn't have to file a dispute.
6. Talk to your processor
Reply to the warning. Say what happened, when it began, and what you have changed. Ask whether the decline rate or any disputes put the account at risk and what they want to see. Card networks track dispute rates, and processors watch both disputes and declines. Showing that you have acted makes restrictions less likely.
7. Monitor so the next wave is caught early
Card testers come back, often to the same store. I set alerts for failed payment spikes, for bursts of orders under a set amount, and for new accounts per hour, and I keep an eye on the firewall event log. Reviewing these weekly turns the next attack from a crisis into a firewall log entry.
If the attack came with other signs of a break-in, such as unknown admins or redirects, read what to do in the first hour after a hack. Ongoing protection like this is part of security, infrastructure and site care.