How to stop card testing
Also called: card cracking · carding · BIN attack · auth testing · card validation attack
What it costs you
- trending_downYour approval rate. Processors and banks watch how many of your charges get declined. A flood of declines marks you as a risky merchant, and they quietly start approving fewer of your real customers.
- trending_downA fee on every attempt. Most processors charge you even when the card is declined. Ten thousand failed attempts is a real invoice for nothing.
- trending_downChargebacks on the cards that did work, plus a chargeback ratio that follows you to every processor you ever apply to.
- trending_downThe processor relationship itself. At worst they hold your money in reserve, raise your rates, or drop you. Finding a new processor in a hurry costs far more than the fraud did.
- trending_downA day of engineering you did not plan for. This attack shows up suddenly and has to be dealt with the same day.
How the attack runs
- 01
Get a list of card numbers
Bought in bulk from a data breach, or generated from a known bank prefix. Nobody yet knows which of them still work.
- 02
Find a cheap, fast place to try them
They are not after your product. They want any form that will attempt a charge with little friction: a donation box, a small top-up, adding a card to an account, a $1 trial. No cart and no shipping address is ideal.
- 03
Run them in bulk, fast
Thousands of attempts at once. Most are meant to fail. What they want is a filtered list, not any single purchase.
- 04
Keep the ones that go through
A card that gets approved is now proven live, and worth far more than an untested number. It usually gets sold on, and often spent somewhere else entirely.
- 05
Spend it somewhere else
This is why you may see almost no theft on your own site. You were the free testing service. The loss lands on another merchant later, and on the cardholder.
What does not work
These are the defences most teams try first. They are listed here because trying them and watching them fail is expensive.
Requiring CVV and billing address
Do it anyway, but do not lean on it. Breached data often includes both. When it does not, the attacker reads your error message to learn which field was wrong. You have made your checkout more useful to them, not less.
Blocking the IPs you saw attacking
The attack has already moved by the time the block goes live. It comes from thousands of addresses and keeps rotating, so your blocklist is always describing the last minute.
A CAPTCHA at checkout
Solving services charge a fraction of a cent, and this attack has a budget. Meanwhile you have added friction at the exact step where a customer giving up costs you the most. Your real customers pay for it.
Raising your minimum charge
It costs the attacker slightly more and stops nothing, because they are not the one paying. What it does reliably is kill a legitimate price tier.
Reading fraud reports once a week
This attack does its damage in hours. Weekly means the first you hear of it is your processor asking why your decline rate looks like that.
The signals that do
These are the signals that carry weight on card testing, and why each one is the signal rather than the obvious alternative. Not all of them are ours: the ones marked you build this genuinely work and Kaidn does not check them, so you would be wiring them up yourself. Listing those unlabelled would read as a claim we cannot support.
Your decline rate, watched live
you build thisThe most reliable sign, and the one people check too late. If the share of charges being declined jumps over a few minutes, treat it as card testing until you prove otherwise. Alarm on the percentage, not the count, so it works on a quiet day and a busy one.
Cards clustered on one bank
you build thisThe first six digits of a card number say which bank issued it. Generated lists clump on one or two of them. Real customers spread across hundreds. A tight clump inside a short window is close to proof.
Counting attempts per person, not per card
Kaidn checks thisAttackers use a different card number every time. Count per card and every counter reads one, so nothing ever trips. Count per device, per session, per IP, per email and per network, and the volume becomes obvious.
The same small amount, over and over
you build thisTesting uses the smallest amount that will go through, again and again. A run of identical small charges, especially overnight, is not shopping.
Signs of a script on the payment page
Kaidn checks thisThis attack is almost always automated. A browser being driven by software, or a card number filled in faster than a person can type, matters most on exactly this page.
Card testing is unusual among the abuse patterns on this site, because the money mostly does not leave through you.
Someone has a list of stolen card numbers and does not know which ones still work. Your payment form tells them, for free, in seconds. They keep the ones that go through and spend them somewhere else.
That changes what you are defending. You are not really protecting your inventory here. You are protecting your relationship with your payment processor, and that is much harder to get back.
The real bill#
A few thousand declined charges cause three separate problems. Only one of them looks like fraud on a report.
The first is fees. Most processors charge you for a declined attempt too, so a big run is a real invoice for nothing. This is the visible one and usually the smallest.
The second is your approval rate, and this is the serious one. Processors and banks watch what share of your charges get declined. A bad ratio reads as a signal about you, not about the attacker, so they start approving fewer of your genuine customers. That drag is permanent and you never see it happen.
The third is the relationship. A sustained pattern can mean they hold your money in reserve, raise your rates, or ask you to leave. That last one is the outcome to design against. Finding a new processor while carrying a bad decline history is slow, expensive, and sometimes not possible on your old terms.
Speed is the whole problem#
Most fraud on this site is a slow leak. You can study it for a week and lose nothing by waiting. This one is different. A card testing run can push tens of thousands of attempts through a form in an afternoon. By the time anyone reads a daily report, the damage is already recorded.
So whatever you build has to act during the attack, not after it. Two consequences. Alarm on percentages rather than totals, and make the response automatic, because waking someone at 3am is not a control.
Count the right thing#
The mistake that lets this run is counting attempts per card.
They change the card number on every request. So every counter reads one, and nothing trips. The thing you made unique is the one thing they were always going to vary.
Count per session, per device, per IP, per network, per email, and per bank prefix instead. The attacker has to reuse something, and it is never the card. It is the same mistake as one-account-per-email in multi-accounting, in a more expensive place.
Where we sit, and where we do not#
We score the payment attempt before it reaches your processor. Four kinds of question:
- Is this a script? A browser being driven by software, or a card number filled in faster than a person can type.
- Is something repeating? How many attempts from this same device, IP, email or session in the last few minutes. Not the card, because they change that every time, and because your processor already counts cards and we never see the number.
- What kind of connection is this? Whether the IP belongs to a home network, a data centre, a VPN, or a network with a history of abuse.
- What kind of email is this? Whether the domain is a throwaway, and whether ten different addresses are really one inbox.
You get back a verdict with the checks that fired and what each one counted for, in a few milliseconds, so you can block the attempt inline rather than review it tomorrow.
What we do not do: we are not a payment processor, so we never see whether a charge was approved or declined unless you send that to us. The strongest version of this defence uses both sides. Your processor has the decline data and we do not. We score the behaviour on the attempt and they largely do not. If your processor offers velocity controls, turn those on as well. This is a layer, not a replacement.
Score the attempt, not the card#
Call us before you call your processor. The identity fields are everything except the card:
const r = await kaidn.score({ event: "payment_attempt", user_id: session.userId ?? undefined, // guest checkout often has none ip: req.ip, email: body.email, device_id: body.kaidn_device_id, }); // this attack is high volume and automated, so repetition and scripting matter most const testing = r.reasons.includes("device_velocity") || r.reasons.includes("ip_velocity") || r.reasons.includes("headless_browser"); if (testing || r.verdict === "block") { await recordSuppressedAttempt(r.event_id); return Response.json({ error: "please try again later" }, { status: 429 }); } return authorise(body); // only now does the card reach your processor
The ordering is the point. An attempt you stop here never becomes a declined charge, and the decline count is the number your processor is actually reading.
The alarm to build first, with no vendor at all#
This is the highest-value hour on this page and it costs nothing. Alarm on the share of charges being declined in a short window, not on a count in a daily report:
SELECT count(*) FILTER (WHERE status = 'declined')::float / nullif(count(*), 0) AS decline_ratio, count(*) AS attempts FROM payment_attempts WHERE created_at > now() - interval '10 minutes' HAVING count(*) > 20;
Page someone when that goes above 0.5, meaning half your attempts are failing. A count threshold misses a slow run and cries wolf on a busy hour. A percentage does neither. Wire it into whatever already wakes somebody up, and make the automatic response a throttle rather than a notification.
What to do this week, before buying anything#
Put a live alarm on your decline rate. Threshold it on the percentage, not a count, and make it fire within minutes. It costs an afternoon, it needs no vendor, and it turns this from something you find out about in an email from your processor into something you catch while it is happening.
Frequently asked questions
What is card testing?
Someone runs a list of stolen card numbers through your payment form to find out which ones still work. Your checkout becomes their free testing tool. The money mostly does not leave through you, which is why this is easy to underrate. What you are actually defending is your standing with your payment processor, and that is much harder to get back than stolen inventory.
What does card testing actually cost me?
Three things, and only one of them looks like fraud on a report. Fees on every attempt are visible, and usually the smallest. A damaged approval rate is the serious one: processors and banks read a poor approval ratio as a signal about you, and the drag then applies to your genuine customers forever. The third is the relationship itself, meaning reserves, worse rates, or being asked to leave.
Why does rate limiting per card not work?
Because the card number is the one thing they change on every single request. Count attempts per card and every counter reads one, so nothing ever trips. Count per session, per device, per IP, per network, per email and per bank prefix instead. The attacker has to reuse something, and it is never the card.
How fast does a defence have to be?
Fast enough to act during the attack. A run can push tens of thousands of attempts through a form in an afternoon, so a daily report is a record of the damage, not a way to stop it. Alarm on percentages rather than totals, fire within minutes, and make the response automatic. Waking a person at 3am is not a control.
Does Kaidn see my declines?
No, not unless you send them to us. Kaidn is not a payment processor, so we never see whether a charge was approved or declined. What we score is the attempt itself, before it reaches your processor: is this a script, is the same device or IP or email repeating, what kind of network is it coming from, is the email a throwaway. The strongest setup uses both. Your processor has the decline data and we do not. We score behaviour on the attempt and they largely do not.
Score your own traffic for this
10,000 events a month free, no card. Every verdict comes back with the checks that fired and their weights, so you can see which signal caught it rather than trusting a number.