The account that drains your referral budget next month was probably created eight months ago. It verified its email, maybe set a profile picture, and then did nothing at all. Every check you run at signup passed, because at signup there was nothing to catch.
This is account farming, and it exists because aged accounts are worth more than fresh ones. Everything defenders key on — account age, email verification, a history of no abuse — is exactly what the farm manufactures and then sells.
Why age is a product
An account with a plausible history clears the checks that a minutes-old account fails: promotion eligibility, marketplace selling privileges, review posting, withdrawal limits, trust tiers. Farms register in bulk when it is cheap, let the accounts sit, and sell them when they have appreciated.
The consequence for you is uncomfortable: age is not evidence of legitimacy, it is an input the attacker controls. Any rule of the form "accounts older than N days skip this check" is a rule the farm has already priced in and waited out.
What the farm cannot go back and change
The accounts are clean now. They were not clean when they were made. A farm registering in bulk is doing it efficiently, which means at registration time those accounts shared things they can never retroactively unshare:
- The machine. A few devices, or a few antidetect browser profiles, produced hundreds of registrations. That link is fixed at creation.
- The network. Datacenter ranges, a proxy pool, or one residential address used far more times than a household would.
- The timing. Registrations clustered in a way organic signups never are — dozens in an hour, then nothing.
- The inputs. Patterned emails, one disposable domain, sequential usernames.
None of that is visible in the account's current state, which is why a fraud check that only ever looks at right now cannot see it. It is visible in what you recorded at signup — if you recorded it.
Store the signup verdict, not just the decision
This is the whole practical lesson. The signal that catches account farming is eight months old by the time you need it, so the question is whether you kept it.
// At signup: persist the evidence, not just allow/review/block.
const v = await sentinel.evaluate({
token: req.body.sentinelToken,
accountId: newUser.id,
});
await db.insert('signup_evidence', {
user_id: newUser.id,
visitor_id: v.device?.visitor_id, // survives IP rotation
linked: v.device?.linked_accounts, // how many of yours share it
times_seen: v.device?.times_seen,
decision: v.decision,
reasons: v.reasons, // machine-readable
network: { vpn: v.network?.vpn, datacenter: v.network?.datacenter },
created_at: Date.now(),
});
Months later, when that account tries to claim a promotion, the useful query is not "is this account old?" but "how many accounts share the device this one was born on?" A farm answers that question badly no matter how long it waits.
Enforce at the payout, not the login
Aged accounts do nothing wrong until the moment they do, and that moment is nearly always a payout: a referral credit, a promotional balance, a first withdrawal, a marketplace listing that finally goes live. That is where the check belongs.
Two reasons. The abuse is concentrated there, so you are spending checks where the money is. And a false positive at a payout costs a support ticket, while a false positive at login costs you a customer who cannot get into an account they have had for a year.
async function payoutGuard(req, res, next) {
const ev = await db.signupEvidence(req.user.id);
if (!ev) return next(); // pre-dates the logging, fail open
const siblings = await db.countAccountsByVisitor(ev.visitor_id);
if (siblings >= 10) {
return res.status(202).json({ status: 'manual_review' });
}
next();
}
Return a review state rather than a refusal. A ring of ten accounts on one device is strong evidence; it is not proof, and households, shared computers and internet cafés all exist.
Picking the sibling threshold
Do not take a number from a blog post, including this one. The right ceiling depends entirely on whether your product is shared in normal life — a family streaming service and a business banking tool have wildly different honest maximums.
Start by measuring rather than blocking. Log the sibling count on every payout for a few weeks, plot it, and find where the distribution stops looking like households and starts looking like inventory. There is usually a visible gap, and it is usually not where you guessed.
What this does not solve
Farms that register accounts one at a time, from genuinely different homes, on genuinely different machines, are indistinguishable from real users at signup — because at that point there is no meaningful difference. What defeats that operation is not detection but economics: it costs so much more per account that the resale margin disappears.
That is the honest goal here. You are not trying to make farming impossible. You are trying to make the cheap version of it stop working, which removes most of the volume, and to make the expensive version cost more than the accounts sell for.
Frequently Asked Questions
Why do account age rules fail against farms?
Because age is the product being sold. Farms register in bulk when it is cheap, let the accounts sit until they satisfy your age threshold, and then sell them. Any rule of the form "older than N days skips this check" is one the farm has already priced in and waited out. Age is an input the attacker controls, not evidence of legitimacy.
What signal actually catches an aged account?
The circumstances of its creation, which cannot be changed afterwards. Bulk registration shares devices, networks, timing and input patterns even when the resulting accounts look clean months later. That means the catching signal is recorded at signup and queried at payout, so the practical requirement is that you stored the signup evidence rather than only the allow/review/block decision.
Where should the check run if not at login?
At the payout — referral credit, promotional balance, first withdrawal, a listing going live. That is where aged accounts finally act, so it is where the spend is justified. It also has the better failure mode: a false positive at a payout costs a support ticket, while a false positive at login locks a year-old customer out of their own account.
How many accounts sharing one device is too many?
Measure it rather than adopting a number. Log the sibling count on every payout for a few weeks and look at the distribution: households, shared machines and cafés produce a small cluster, and inventory produces a separate one further out. The gap between them is your threshold, and it depends heavily on whether your product is normally shared.
Record the evidence while it still exists
A device identifier that survives IP rotation, plus how many of your accounts already share it, in one call at signup. Free at 1,000 requests an hour, no card.
Get a free API key