Stop account takeover from inside your app.
srvAudit ATP sits on your login path, not in front of it — so it scores behaviour instead of addresses. Two calls to wire up, and it blocks nothing until you say so.
Ships observing-only. You look at the numbers before anything is ever blocked.
Built for automated credential abuse
Different names, one shape: software working through a list against your login form, patient enough to stay under every threshold you have.
Credential stuffing
Username and password pairs from somebody else's breach, replayed against your login. Each account gets one or two attempts, so nothing looks unusual per account or per address.
Password spraying
A handful of predictable passwords tried against every account you have, paced slowly enough that no individual account ever reaches a lockout threshold.
Targeted brute force
One valuable account, many passwords, spread across a wide enough pool of addresses that a per-address limit never sees a pattern.
Scripted clients
Traffic presenting your own app's user agent and headers, with a device identifier that changes on every request so it can never be pinned down or banned.
Many addresses, one behaviour. Detect the behaviour, not the addresses.
Every one of these is engineered to sit under whatever limit you set. Rate limits, reputation lists and geo-blocks are defeated by the same arithmetic. What separates an attacker from your users is not where they come from — it's how they behave.
Why the arithmetic beats you
An illustrative distributed stuffing campaign. The magnitudes vary enormously between targets — the ratio is the part that stays the same.
- 40,000
- login attempts / hour
- against one endpoint
- 18,000
- distinct addresses
- consumer broadband and proxies
- 2.2
- attempts per address
- fewer than a forgetful user
- 6%
- on any reputation list
- the rest look ordinary
At a couple of attempts per address, any limit loose enough to let one real person log in also lets the whole campaign through. Tighten it and you start rejecting families behind a shared connection, offices behind one gateway, and anyone who fat-fingers a password twice. There is no setting that separates them, because the distinguishing information isn't in the address at all.
What a network-edge product can't see
AWS WAF ATP is a capable product. It is simply standing in the wrong place for this class of attack.
It knows logins are failing. Not whose.
An edge product reads your status codes and gets an aggregate failure rate — a blunt number that rises on a bad Monday morning as readily as during an attack. It cannot attribute a failure to an account, so it cannot tell one account being sprayed from a thousand people mistyping. Acting on the aggregate means acting on everyone.
The addresses are clean
A residential-proxy botnet has ordinary consumer reputation. Anonymous-IP lists catch under 5% of it. Reputation-based signals barely register.
The client is a convincing forgery
A valid user agent, the full set of your app's custom headers, and a device identifier that rotates on every single request. Edge fingerprinting sees a plausible app because it is being shown one.
Per-account history stays on your server
Which account was tried, how often, from how many devices, and whether the last attempt was a wrong password or a correct one awaiting a second factor — none of that leaves your application. To get it, an edge product would need you to hand it your login payloads. We never ask for them.
Two mechanisms. That's the whole product.
Everything else is configuration and telemetry. Both mechanisms are levers you turn at runtime, without a deploy.
The token gate
A client solves a small proof-of-work puzzle on-device to mint a short-lived signed token, then attaches it to the login request. Address rotation is irrelevant to did you complete the handshake, so spreading a campaign across tens of thousands of addresses buys nothing.
- Validated statelessly — a constant-time signature check, no database read on your login path.
- Difficulty is a live dial. Each extra bit doubles the attacker's minting cost.
- Keys rotate with zero downtime: sign with the current key, verify against current and previous.
- Per-address mint caps and one-time redemption stop bulk token farming and replay.
Behavioural scoring
For the attacker who does hold a valid token. The governing principle is positive evidence, not a blocklist: a request has to prove it belongs to a real session. A fresh identifier with no history can't prove anything — which is exactly why rotating identifiers doesn't evade it, and why it can never be turned into a way to lock out one of your users.
Impossible client version
Claims a version that was never shipped
No session provenance
Jumped straight to login, skipped your app's startup sequence
Invariant fingerprint
A field a real population varies, held constant
Device account spread
One device, many distinct accounts
Block threshold: 60. No single weight reaches it, so a block always needs at least two independent signals agreeing. One noisy signal can never block on its own.
It cannot take your logins down
A protection that can break authentication is a worse problem than the one it solves. Four properties make that structurally impossible.
Fails open
The client in your app uses a 50ms connect and 150ms read budget and swallows every exception. Any error or timeout is treated as allow. An outage on our side costs you protection, never logins.
Observes before it enforces
Every site ships in count mode. The verdict is always allow; you get the would-have-blocked volume as telemetry. You decide to enforce after looking at real numbers.
One-field rollback
Switching back to observing is a single field in the portal, live within a minute. No code rollback, no redeploy, ever.
Cannot lock out an account
A request carrying a valid token is never blocked by the per-account threshold. Otherwise an attacker could burn a victim's counter with two cheap puzzles and lock the real owner out.
The attacker sets your AWS bill. Not ours.
AWS WAF ATP charges $1.00 per 1,000 login attempts inspected, on top of the WAF base fees. The inspection you're paying for scales directly with the attack — the harder you're hit, the more the protection costs. Our plans are flat, with overage priced 50× lower.
Starter
$19 / month
per protected site
- 250,000 login attempts / month included
- Then $0.02 per 1,000
- 30 days of telemetry retention
- Token gate and behavioural scoring
- Every lever tunable at runtime
- Managed from your srvAudit portal
AWS WAF ATP at the same volume: $265.15 / month
Choose StarterGrowth
$49 / month
per protected site
- 2,000,000 login attempts / month included
- Then $0.015 per 1,000
- 90 days of telemetry retention
- Token gate and behavioural scoring
- Every lever tunable at runtime
- Managed from your srvAudit portal
AWS WAF ATP at the same volume: $2,016.20 / month
Choose GrowthScale
$149 / month
per protected site
- 10,000,000 login attempts / month included
- Then $0.01 per 1,000
- 365 days of telemetry retention
- Token gate and behavioural scoring
- Every lever tunable at runtime
- Managed from your srvAudit portal
AWS WAF ATP at the same volume: $10,021.00 / month
Choose ScaleWhat the same month costs
AWS figures use published list prices: $5 web ACL, $10 ATP rule group, $0.60 per million requests, and $1.00 per 1,000 login attempts inspected.
| Login attempts / month | AWS WAF ATP | srvAudit ATP | You keep |
|---|---|---|---|
| 250K A small app, quiet month | $265.15 | $19.00 Starter | 92.8% $246 / month |
| 2M A busy app, normal traffic | $2,016.20 | $49.00 Growth | 97.6% $1,967 / month |
| 10M Large app, or light attack | $10,021.00 | $149.00 Scale | 98.5% $9,872 / month |
| 90M Under sustained credential stuffing | $90,069.00 | $949.00 Scale | 98.9% $89,120 / month |
The bottom row is the point. Under sustained attack, AWS bills you for every one of the attacker's attempts.
What we deliberately don't do
srvAudit ATP is the in-app layer. It is more basic than AWS's offering by design, and it is not a replacement for a WAF. If you need edge filtering or volumetric defence, run both — they solve different problems and ours costs a rounding error next to the attack it's absorbing.
It is also a layered, evolving defence rather than a wall. Each behavioural counter forces an attacker to impersonate more of your application's real lifecycle — more requests, more cost, more fingerprintable surface. That cost shift is the win, not a permanent block.
Three calls on your auth path
Ask before you authenticate, tell us what actually happened afterwards, and mark the pre-login steps a real client performs. Every call is fail-open with a tight timeout, so the worst case is that you lose protection — never a login.
- verify
- Before you authenticate
- Should I allow this attempt? Returns a verdict, the reasons behind it, and the behavioural score.
- report
- After you authenticate
- What actually happened — success, failure, MFA pending, or locked, attributed to the account that was tried. This is what turns a raw failure count into per-account accounting.
- observe
- On your pre-login endpoints
- This client just performed startup step X. Builds the session provenance the boot-trail signal reads.
public function store(LoginRequest $request)
{
$context = Atp::contextFrom($request);
// Fails open: any error or timeout allows.
if (Atp::verify($context)->blocked()) {
return back()->withErrors([
'email' => __('auth.failed'),
]);
}
$result = $this->attemptLogin($request);
// Attributes the outcome to the account that was tried.
Atp::report($context, $result);
return $result->successful()
? redirect()->intended()
: back()->withErrors([...]);
}
Turn it on in observing mode. Decide later.
Add a site from your srvAudit portal and you'll have a server key and an integration snippet in under a minute. Nothing is ever blocked until you look at the numbers and choose to enforce.