Legitimate traffic getting rate-limited or banned

Telling apart the three things that can block a real user - sliding-window rate limit, auto-ban, threat-ban - and tuning each without disabling protection.

5 min read · verified against [email protected]

Three separate mechanisms can block a legitimate user, and they are tuned differently. Treating them as a single "blocking" problem leads to the wrong fix.

Symptom: real users hitting 429 or bans

A user reports being blocked. The dashboard shows activity from their IP. They are not an attacker.

Is it rate limit, auto-ban, or threat-ban?

MechanismResponse codeTriggerKnob
Rate limit429Too many requests in the sliding windowrate_limit, rate_limit_window
Auto-ban403Strike counter (rate-limit + detections combined) over auto_ban_thresholdauto_ban_threshold, auto_ban_duration
Threat-ban403Detections of a specific attack class over the per-class thresholdthreat_ban_config["<class>"]

A 429 with no prior ban history is almost always a rate-limit issue. A 403 requires checking whether the IP was auto-banned via the shared strike counter or threat-banned via a detection class.

Reading the event to tell which

Open the Events page in the dashboard and filter by the affected IP. The event type tells you which mechanism fired:

  • rate_limit_exceeded - the sliding-window counter fired. The IP hit too many requests within the window.
  • ip_banned following a trail of rate_limit_exceeded events - the shared strike counter crossed auto_ban_threshold. Both rate-limit violations and detections contribute to this counter; an IP that trips the rate limiter repeatedly can accumulate enough strikes to escalate to a ban.
  • ip_banned with no preceding rate_limit_exceeded events, or following penetration_attempt / behavioral_match events - a threat_ban_config per-class threshold was reached. Check the Redis ban record ({redis_prefix}banned_ips:{ip}) to confirm the ban is present and to inspect its TTL.

If the dashboard shows no events at all for the IP but the user reports 403, the IP may already be in the ban list from a previous window. Check Redis directly:

EXISTS {redis_prefix}banned_ips:{ip}
TTL {redis_prefix}banned_ips:{ip}

See Rate limiting & auto-ban for the mechanics of each mechanism.

Tuning without disabling

Rate limit false positive - the user's traffic is legitimate but high-volume (a data-export job, a mobile app's background sync, a CI pipeline hitting your API).

Options:

  • Raise rate_limit or rate_limit_window globally, or add a per-route override with a higher limit for the affected endpoint.
  • For known high-volume IPs (internal services, trusted partners), a whitelist or per-route higher limit is more targeted than raising the global.

Do not disable rate limiting entirely. Per-route overrides let you raise limits on specific endpoints without changing the global posture. See Rate limiting & auto-ban.

Auto-ban false positive - the user is legitimately hitting the API frequently but not maliciously. The strike counter is shared between rate-limit violations and detections, so an IP that trips the rate limiter repeatedly can accumulate strikes and escalate to a ban.

Options:

  • Raise auto_ban_threshold to require more strikes before a ban fires.
  • If the traffic pattern is expected (corporate NAT where many users share an IP, mobile CGNAT), raise both rate_limit and auto_ban_threshold together.
  • To unban immediately, delete the Redis key: DEL {redis_prefix}banned_ips:{ip}. Note: the in-memory hot cache is not immediately invalidated, so the ban may persist on individual workers until the cache entry expires.

See Rate limiting & auto-ban for how rate-limit violations and detections share the strike counter.

Threat-ban false positive - a legitimate request triggered a detection pattern (a parameter value that resembles a SQLi probe, a path that matches file-inclusion patterns).

Options:

  • Check the specific detection class in the event. Was it file_inclusion from a honeypot path the user legitimately needs? Was it sqli from a search query with SQL-like syntax?
  • If a specific path should not trigger detection, use detection exclusions to exempt it.
  • Adjust the threat_ban_config threshold for that class to require more detections before a ban, but only if you are confident the false-positive rate is high enough to justify it.

See Honeypots & threat-based banning for the difference between auto-ban and threat-ban and how each threshold works.

Geo or cloud block false positive

A 403 with no ban record in Redis and no event in the dashboard may be a geo or cloud block. These operate earlier in the pipeline and do not emit events to the dashboard.

Geo block: the user is connecting from a country in blocked_countries, or the route carries a decorator-level whitelist_countries and the user is outside it. A global whitelist_countries only exempts countries from the block list. It does not block the rest of the world on its own (see blocked_countries vs whitelist_countries). If the user's location is unexpected (VPN, travel, cloud-based development environment), they will hit the geo block.

Cloud block: block_cloud_providers contains the provider whose IP range the user's traffic originates from. Corporate offices that route through cloud-hosted proxies, or developers on cloud-based IDEs, can appear as cloud-originating traffic.

Options:

  • Confirm the resolved client IP in the event, then look up the IP to confirm the geo or provider match.
  • If the block is for a legitimate user, adjust blocked_countries / whitelist_countries or remove the offending provider from block_cloud_providers.
  • Note that block_cloud_providers values are case-sensitive: "AWS", "GCP", "Azure". Lowercase or alternate forms are silently ignored.

See Geo + cloud-provider blocking for how each mechanism works and what each is appropriate for.