Card testing
Card testing is fraud where bots run stolen card numbers through your checkout to find live ones. Learn the signs in Stripe, the costs, and how to stop it.
Updated October 1, 2026
Card testing is fraud in which someone runs a list of stolen or guessed card numbers through your checkout to find out which ones still work. They don't want your product. They want a list of valid cards to use elsewhere or sell. Stripe also calls it carding, account testing, enumeration or card checking. Any business with a public payment form can be a target, including a small SaaS signup page or a donation form.
How a card testing attack works on Stripe
Testers run scripts that try many cards fast and record the issuer or 3D Secure response for each one. Stripe describes two main routes:
- Card setup. Saving a card, for example through a SetupIntent or by attaching a card to a new customer, is the route attackers prefer. Validations during setup don't usually show up on the cardholder's statement.
- Small payments. Low charges are less likely to be noticed or reported by the cardholder.
Your publishable key is public by design, so testers can call your payment flow directly. If your secret key leaks, they can create payments and save cards with it too.
In your account, an attack is a burst of events. Declined attempts fire payment_intent.payment_failed and charge.failed. Attacks on card setup fire setup_intent.setup_failed. Days or weeks later, the cards that went through produce radar.early_fraud_warning.created and charge.dispute.created.
Signs of card testing
Stripe says most attacks are easy to spot once you look. Watch for:
- A spike in failed or blocked payments on the Dashboard home page and the payments list.
- A spike in 402 card errors in your developer logs, often with a
generic_declineoutcome. - A wave of small successful payments from customers with nonsense names or email addresses.
- Many new customers created in quick succession.
What card testing costs
- Disputes. Some test charges succeed. The real cardholders spot them and report fraud, which leads to early fraud warnings and fraud disputes, each with a dispute fee.
- More declines for real customers. A pile of declined payments makes your business look riskier to issuers, and they can decline more legitimate payments after the attack ends.
- Fees. Custom pricing plans can include authorization fees, on top of dispute fees.
- Network monitoring. Visa's Acquirer Monitoring Program tracks enumeration separately from disputes and fraud, so an attack alone can put you in monitoring.
- Bad data. Test payments look like new customers and revenue in your metrics.
How to stop a card testing attack
Stripe's checklist is to identify the activity, refund fraudulent payments, add mitigations, and keep monitoring. In practice:
- Confirm and contain. Check the Dashboard and logs for the failure spike. If an endpoint saves cards or takes payments without protection, add rate limits such as a cap on new customers per IP address per day. Require a login or session before payment, or put a server-side CAPTCHA in front of it.
- Use a recommended integration. Stripe says the latest Payment Element and Checkout include card testing controls such as rate limiters, AI models and CAPTCHA triggers. Attempts they stop show as "Blocked by Stripe".
- Refund what got through. Refund suspicious successful payments before cardholders dispute them. Use the reason
fraudulent, which also feeds Stripe Radar. - Don't retry the stolen cards. Stripe warns that retrying cards saved on fraudulent customers repeats the attack. Remove those customers from any retry or dunning flow.
- Rotate keys if you suspect a leak. If the attack used your secret key, your checkout form isn't the problem.
- Tighten Radar. Radar's built-in rules include CVC checks. Plans with custom rules let you write velocity rules for the attack you're seeing.
Spotting an attack in Slack
Card testing is a volume problem, so the fastest signal is a sudden rise in failed payments. ChargeBell's failed payment alert posts to Slack on each payment_intent.payment_failed, with the amount, the customer and the decline reason. It is a critical alert, so it skips quiet hours and can @channel. That matters because attacks often run overnight. One alert is a customer problem. A stream of alerts for tiny amounts, with generic declines and odd email addresses, is an attack. Send failures to a channel such as #billing where someone with Stripe and engineering access is watching. The Stripe decline codes cheat sheet explains the decline reasons.
Get alerted in Slack
Stripe events: payment_intent.payment_failed, charge.failed, setup_intent.setup_failed, radar.early_fraud_warning.created, charge.dispute.created
ChargeBellAPP
⚠️ A $149.00 payment didn't go through
@channel
acme@example.com · Your card has insufficient funds.
Check Stripe to see if it will be retried.