Coordinated attack detection

Detecting many tor, proxy, residential or datacenter IPs acting as one coordinated attack, when no single IP trips a per-IP ban.

5 min read · verified against [email protected]

The standalone guard-core library blocks and bans per IP. That catches the loud attacker: one IP hammering /login until it crosses auto_ban_threshold. It does not catch the patient attacker who spreads the same load across dozens of tor, proxy, residential or datacenter IPs, each one staying just under the ban threshold. The SaaS detects that cross-IP coordination in real time. This is a SaaS-only capability; the library cannot see it because it has no cross-instance, cross-IP view.

The coordinated distributed attack problem

A coordinated distributed attack is many IPs acting as one attack. The giveaway is the aggregate shape, not any single IP:

  • 15 residential-proxy IPs each send 4 requests to /login in the same 300-second bucket.
  • Per-IP auto_ban_threshold is 10. No single IP reaches it. Per-IP detection fires on none of them.
  • 60 coordinated requests still hit your login endpoint. Per-IP and per-instance tracking miss it because every individual IP looks ordinary.

This is the escalation path past behavioral detection: behavioral rules count per IP within a window. Coordinated attacks are designed so that no per-IP counter ever trips. The SaaS correlates across IPs to find the attack that per-IP rules are built to miss.

How the SaaS detects it

The coordinated detector runs server-side on the aggregated event stream from all your instances. It does not run in the in-process library.

Distinct-IP counting with HyperLogLog. The detector keeps a HyperLogLog sketch of distinct source IPs keyed by organization, endpoint and event type inside a fixed 300-second bucket, not per project and not a sliding window. HyperLogLog gives an approximate distinct count with bounded memory, so tracking thousands of distinct attacking IPs costs roughly the same as tracking a handful. A bucket qualifies on volume once it accumulates 60 or more events and 15 or more distinct IPs, both hardcoded constants, then qualifies on origin once at least half of those distinct IPs classify as automation.

Automation classification. Volume alone is not enough; a viral link can throw many residential IPs at an endpoint harmlessly. Each source IP is classified by proxy class: tor, proxy, residential, datacenter, or unclassified. The detector requires the distinct-IP burst to be dominated by IPs that resolved to any of the four classified types, tor, proxy, residential, or datacenter, not unclassified traffic. Datacenter counts here because botnets and scripted attackers commonly run from cloud infrastructure just as often as from residential proxy pools. That is what separates a coordinated attack from a traffic spike.

Per-IP overcap gate. Each IP's events count toward the bucket's totals only up to a hardcoded cap of 10 per bucket; once an IP crosses that cap, its further events in the same bucket stop incrementing the event count. This has nothing to do with auto_ban_threshold; it exists so one very chatty IP cannot inflate the bucket's volume on its own.

Fire once via a dedup latch. A coordinated attack is one incident, not 15 per-IP incidents. When the detector trips, a dedup latch keyed by organization, endpoint, event type and the 300-second bucket ensures it fires at most once for that bucket. An attack that spans several buckets produces one match per bucket, not one incident that later buckets merge into; there is no open incident for it to update.

Daily FSM replay. The realtime path catches attacks as they happen. A second, independently thresholded set of built-in coordinated patterns replays the last 24 hours of events once a day at 05:00 UTC, each pattern with its own distinct-IP, event-count and window numbers rather than the realtime path's fixed 15-IP, 60-event, 300-second bar. This is not the same detector running with relaxed numbers: coordinated_slow_brute_force, for one, watches a 4-hour window the realtime path's 300-second bucket cannot express. Anything the replay catches is written to the dashboard alongside the realtime matches.

Alerting

When the detector fires, one alert is dispatched per match (not per IP) through the configured channels: Slack, Discord and PagerDuty, wired from Settings -> Integrations. Slack and Discord post a message titled "Coordinated attack detected" carrying the endpoint, event type, distinct-IP count, proxy fraction, severity and a link to the attack detail. PagerDuty gets a summary of Coordinated attack detected: {distinct IPs} IPs on {endpoint} with the same fields in its custom details and severity taken from the match.

The coordinated attacks dashboard

The dashboard lives at /coordinated-attacks.

The list view shows each match's endpoint, event type, distinct-IP count, proxy fraction, severity and detected time, most recent first.

The detail view (/coordinated-attacks/[id]) shows the same endpoint, event type and distinct-IP count, plus the raw proxy-IP count behind the proxy fraction, severity, detected time, and the match's source, realtime_hll or daily_fsm, telling you whether it came from the streaming detector or the daily replay.

For a scripted attacker who rotates across endpoints instead of hammering one, see Campaign detection.

For the broader incident workflow (status transitions, breach notifications, reports), see the dashboard documentation, available with an account.

Tier gating

Coordinated attack detection is gated to Team, Business, and Enterprise plans. The Individual and Pro plans do not include it, and the /coordinated-attacks dashboard shows an upgrade prompt on those tiers.

If you are on a gated tier and the dashboard is empty, confirm your agents are shipping events to the SaaS (see the quickstart guide) and that the relevant endpoints are receiving enough volume for the distinct-IP sketch to populate.