Token Buckets, Sliding Windows, and the Rate Limiting Gaps Attackers Exploit Before Your Team Notices

By IPThreat Team June 24, 2026

The Wrong Mental Model Is the Real Vulnerability

Most security teams treat rate limiting as a simple on/off switch — you configure a threshold, something trips it, traffic gets blocked, and the problem goes away. This framing causes more API exposure than almost any misconfiguration teams would recognize as a flaw. Rate limiting is not a single control. It is an architecture decision that touches authentication flows, business logic, abuse detection, and infrastructure resilience simultaneously. Teams that treat it as one setting in a WAF configuration panel are building a floor with holes in it.

The practical consequence is that sophisticated automated abuse sails through rate limiting configurations that look correct on paper. The eBanking phishing campaigns recently observed using IPv4-mapped IPv6 addresses to evade detection illustrate exactly this pattern: attackers probe for the seams between how a system parses an identifier and how a rate limiting policy applies to that identifier. Your limiter sees 127.0.0.1. The IPv6-aware request presents ::ffff:127.0.0.1. If your normalization logic treats those as different identifiers, an attacker just doubled their effective request budget without changing anything about their behavior.

This article walks through the algorithms that actually matter, the implementation details that determine whether a rate limiter holds under adversarial load, and the operational decisions that separate teams who catch abuse early from teams who find out about it from a customer complaint.

Four Algorithms and What Each One Actually Protects

Choosing a rate limiting algorithm is not a theoretical exercise. Each algorithm has specific failure modes under attack, and understanding those failure modes determines where you deploy which algorithm and why.

Fixed Window

Fixed window counters are the simplest implementation: count requests per identifier within a time window, reset the counter when the window expires. A limit of 100 requests per minute means the counter increments on every request and rejects anything above 100 until the window resets.

The attack against fixed window is straightforward. An attacker who knows your window boundary can send 100 requests at 11:59:59 and another 100 requests at 12:00:00, landing 200 requests in two seconds without triggering any limit. This is called a boundary burst attack, and it is exploitable against any fixed window implementation that resets hard at interval boundaries. For authentication endpoints — exactly the ones targeted in credential stuffing campaigns like those used against Instagram accounts via Meta's AI support bot — this two-second burst is enough to test hundreds of username/password pairs if your window is set at the minute level.

Sliding Window Log

Sliding window log implementations store a timestamp for every request from an identifier and count how many timestamps fall within a rolling window on each new request. The window slides forward with time, so there is no reset boundary to exploit.

The tradeoff is memory cost. Storing per-request timestamps for every active identifier at scale is expensive. At high traffic volumes, a sliding window log implementation can become a denial-of-service vector in itself — an attacker who knows you are using this approach can create many low-volume identifiers that each accumulate timestamps, consuming memory without ever triggering a rate limit. This is a real concern for public APIs handling unauthenticated traffic where identifier creation is essentially free.

Sliding Window Counter

The sliding window counter approximates the sliding log behavior with a fraction of the memory cost. It keeps two counters — one for the current window and one for the previous window — and calculates an approximate current request count as a weighted sum based on how far through the current window you are.

The formula looks like this: current_count = previous_window_count * (1 - elapsed/window_size) + current_window_count. This approach is accurate enough for most abuse prevention use cases and is the algorithm behind Redis's recommended rate limiting implementation. The approximation error is bounded and predictable, which makes it suitable for production use at scale.

Token Bucket and Leaky Bucket

Token bucket implementations give each identifier a bucket of tokens that refills at a fixed rate. Each request consumes a token. When the bucket is empty, requests are rejected. The key property is that burst traffic is allowed up to the bucket capacity, while sustained throughput is bounded by the refill rate.

Token bucket is the right choice for APIs where legitimate users have bursty traffic patterns — a mobile app that syncs data when it reconnects to network, for example. Leaky bucket is the inverse: requests enter a queue and are processed at a fixed rate, smoothing out bursts rather than permitting them. Leaky bucket is appropriate when you need predictable output rate regardless of input pattern, such as protecting a downstream service with strict throughput limits.

The attack surface for token bucket implementations is bucket capacity misconfiguration. If your bucket holds 1,000 tokens and refills at 10 tokens per second, an attacker who has been idle for 100 seconds can send 1,000 requests in a burst before hitting any limit. For credential stuffing against a login endpoint, 1,000 attempts per identifier per burst is too many. Bucket capacity needs to be set based on what a legitimate user would plausibly accumulate, not on what makes the math convenient.

Identifier Selection Is Where Most Rate Limiters Fail

The most technically correct algorithm deployed against the wrong identifier does nothing useful. Identifier selection is where rate limiting configurations fail silently — the limiter is running, counters are incrementing, and the attack proceeds unimpeded because the attacker is rotating the identifier faster than the limit accumulates.

IP Address as Identifier

IP-based rate limiting is necessary and insufficient simultaneously. It is necessary because it is the only identifier available for unauthenticated traffic. It is insufficient because IP addresses are not stable identifiers for attackers. Botnet operators running credential stuffing campaigns routinely rotate across thousands of IPs, keeping per-IP request counts well below any threshold you would set without blocking legitimate users. The student loan breach exposing 2.5 million records and the Xolis health tech breach affecting 1.4 million people both involved automated data extraction — the kind of attack where IP-level rate limiting alone provides minimal friction to a competent operator.

The IPv4-mapped IPv6 address technique observed in recent eBanking phishing delivery is a direct exploit of this gap. If your rate limiter treats 192.168.1.1 and ::ffff:192.168.1.1 as different identifiers, an attacker can bypass per-IP limits trivially. Address normalization must happen before rate limiting logic runs, and your normalization must handle IPv6 address representation consistently including compressed forms, expanded forms, and IPv4-mapped representations.

User Account as Identifier

For authenticated endpoints, rate limiting against the user account is more meaningful than rate limiting against IP. An attacker who has compromised one account and is using it to scrape data is identifiable by account behavior regardless of what IP they use. Account-level limits catch this where IP limits do not.

The combination matters more than either alone. Rate limit against IP for pre-authentication traffic. Rate limit against account for post-authentication traffic. Rate limit against the combination of IP and account for login attempts specifically — this catches both credential stuffing (many accounts from one IP) and distributed credential stuffing (one account from many IPs).

Fingerprinting Beyond IP

For higher-value endpoints, behavioral fingerprinting provides a third layer. HTTP headers, TLS fingerprints, request timing patterns, and user agent strings each carry signal. Individually, none of these is reliable. In combination, they create a fingerprint that is harder to rotate than an IP address.

JA3 TLS fingerprinting is worth implementing at the WAF or load balancer layer for APIs handling sensitive operations. Automated tools tend to produce consistent TLS fingerprints across different source IPs because the fingerprint reflects the TLS library configuration, not the source address. SprySOCKS, the Windows implant recently associated with FishMonger, uses network communication patterns that would produce consistent behavioral signatures detectable through traffic analysis — the same principle applies to API abuse tooling.

Where Rate Limiting Gets Deployed Versus Where It Needs to Be

Rate limiting at a single layer is fragile. Production API architectures need rate limiting at multiple layers for different reasons, and the policies at each layer should be calibrated independently.

Edge Layer

Edge rate limiting happens at the CDN or WAF before traffic reaches your infrastructure. This layer handles volumetric attacks — the kind of flooding that would overwhelm application-layer processing before any business logic runs. Edge rate limits should be set permissively enough to avoid blocking legitimate traffic spikes, but tight enough to prevent bandwidth exhaustion. Thresholds here are measured in requests per second across large windows, not fine-grained per-user controls.

CDN-level rate limiting has one important limitation: CDN providers share infrastructure across customers, and some CDN IP ranges appear in legitimate traffic from other CDN customers. Blocking at the CDN layer based on source IP can create collateral blocking problems if your policies are too aggressive. Configure edge rate limiting against volumetric patterns rather than trying to do fine-grained abuse detection at this layer.

API Gateway Layer

The API gateway is where per-endpoint and per-identifier rate limiting should live. This is the layer that understands API structure — it knows that /api/v1/login and /api/v1/search should have different limits, that authenticated and unauthenticated callers deserve different treatment, and that certain endpoints warrant stricter controls based on data sensitivity.

Gateway-layer rate limiting should implement different policies per endpoint class. Authentication endpoints warrant the strictest limits. Data export endpoints need limits calibrated to prevent bulk extraction. Read endpoints can be more permissive. Admin endpoints should have the most restrictive limits combined with alerting on any threshold approach, not just breach.

Application Layer

Application-layer rate limiting catches what the gateway misses: business logic abuse. A request to /api/v1/search with a rotating list of search terms, each consuming one unit of rate limit quota, is indistinguishable from normal traffic at the gateway. The application layer knows that this search pattern is anomalous because it has access to context the gateway does not: search history, result pagination patterns, account behavior over time.

Implementing rate limiting at the application layer means building it into your services, not bolting it on afterward. Redis-backed token bucket or sliding window counter implementations work well here. Libraries like ratelimit for Go or django-ratelimit for Python provide reasonable starting points, but the configuration decisions still require deliberate calibration.

Distributed State and the Synchronization Problem

Single-instance rate limiting is straightforward. Distributed rate limiting — across multiple API gateway instances, across multiple data centers — introduces synchronization problems that create exploitable gaps if you do not account for them.

The naive approach to distributed rate limiting gives each instance its own counter. An attacker making requests that round-robin across ten gateway instances can send ten times the per-instance limit before any single instance registers a threshold breach. This is a real attack pattern against horizontally scaled APIs, and it works against a surprisingly large number of production deployments.

The correct approach uses a shared backing store for rate limit counters. Redis with its atomic increment operations is the standard choice. The INCR command in Redis is atomic, which means concurrent increments from multiple gateway instances against the same key produce accurate counts. The implementation using Redis INCR combined with TTL-based window expiry looks like this: increment the counter for the identifier-window key, set a TTL if the key is new, check the counter value against the limit, and reject or allow accordingly.

The remaining problem is network latency to the shared store. A Redis round-trip adds latency to every rate-limited request. For high-throughput endpoints, this matters. Strategies to manage this include local caching of counts with periodic Redis synchronization (accepting some inaccuracy), using Redis Cluster to reduce latency through geographic distribution, and applying rate limiting only to the subset of traffic that matches risk indicators rather than to every request.

Calibrating Thresholds Without Blinding Yourself

Setting thresholds too low blocks legitimate users. Setting them too high provides no meaningful protection. Neither failure mode is obvious until it causes a problem, and calibration requires data rather than intuition.

Start with traffic analysis of your current baseline. For each endpoint you want to rate limit, calculate the 95th and 99th percentile request rates per identifier across a representative traffic window. Legitimate users cluster below the 95th percentile in most cases. Your initial threshold should sit at approximately two to three times the 99th percentile, then decrease toward the 99th percentile as you monitor for false positives.

Build observability into your rate limiting implementation from the start. Every rate limit decision — allow, warn, and reject — should emit a metric with the identifier type, endpoint, and threshold comparison. This telemetry lets you track the ratio of warnings to rejections to total traffic over time, which is how you detect that a threshold is either too tight (lots of warnings from legitimate traffic) or too loose (no warnings before attacks breach it).

Shadow mode deployment is valuable for new rate limiting policies on existing endpoints. In shadow mode, the rate limiter evaluates every request and records what decision it would have made, but does not actually enforce the limit. Running in shadow mode for a week before activating enforcement shows you exactly which legitimate users would have been blocked and lets you tune thresholds before causing user-facing impact.

Responding to Rate Limit Breaches

What happens after a rate limit is exceeded matters as much as the limit itself. Returning a standard 429 response with a Retry-After header is correct behavior for legitimate clients that are temporarily over quota. For adversarial traffic, a 429 response is also a signal — it tells the attacker exactly what threshold they hit and lets them calibrate their request rate to stay below it.

A more effective approach for suspected adversarial traffic is to return degraded responses rather than explicit rejections for some percentage of over-limit requests. Returning slower responses, incomplete data, or slightly incorrect results without indicating that rate limiting is active makes it harder for an attacker to determine whether they are hitting a limit or experiencing normal API behavior. This technique, sometimes called a tarpit response, is particularly effective against automated abuse that makes decisions based on response success rates.

For endpoints where you have high confidence that over-limit traffic is adversarial, blocking the identifier at the firewall level for a penalty period is appropriate. Temporary firewall blocks triggered by rate limit breaches give your infrastructure relief without requiring manual intervention. This approach works well combined with threat intelligence feeds: if an identifier triggering rate limits also appears in IP reputation data, the block duration can be extended automatically.

The AI supply chain threat landscape highlighted by tools like OpenClaw's Skill Marketplace creates a specific concern here: AI agents making API calls on behalf of users may have legitimate reasons for higher request rates than individual users, but they also provide cover for abuse. Rate limiting policies for API endpoints consumed by AI agents need to account for the orchestration patterns those agents use while still detecting when an agent is being used as an abuse vector.

Monitoring Rate Limiting as a Security Signal

Rate limit telemetry is threat intelligence if you treat it that way. A sudden spike in 429 responses against your authentication endpoint is an early indicator of credential stuffing. A distributed pattern of requests all approaching but not breaching your limit from many different IPs is a sign of threshold probing. Rate limit counters approaching but not exceeding thresholds across many identifiers simultaneously suggests coordinated reconnaissance.

Build alerting on rate limit approach rates, not just breach events. An endpoint that normally sees 1% of requests reach 80% of the rate limit threshold should alert if that percentage rises to 10% within a short window. This leading indicator gives your team time to investigate before an attack scales up to the point of causing service impact.

Correlate rate limit data with authentication logs. Credential stuffing attacks typically show up as rate limit events in your API logs before they show up as account lockouts in your authentication logs. The attackers who hit 2.5 million student loan records and 1.4 million health records moved through API endpoints before any account-level detection triggered. Rate limit telemetry correlated with authentication failure rates would have provided earlier signals in both cases.

Practical Implementation Checklist

  • Normalize IP addresses before applying rate limiting logic. Handle IPv4, IPv6, and IPv4-mapped IPv6 addresses as unified identifiers.
  • Deploy different algorithms per endpoint class. Token bucket for bursty legitimate usage patterns, sliding window counter for authentication and sensitive data endpoints.
  • Use a shared distributed backing store for counter state across all gateway instances. Do not rely on per-instance counters in horizontally scaled deployments.
  • Set thresholds based on measured traffic baselines, not intuition. Use shadow mode before enforcing new policies on existing endpoints.
  • Emit rate limit decisions as structured metrics. Track approach rates and breach rates separately per endpoint and identifier type.
  • Implement penalty periods for confirmed adversarial identifiers triggered by rate limit breaches combined with reputation signals.
  • Review rate limit configurations after any significant traffic pattern change: new API versions, marketing campaigns, product launches, and security incidents all shift what normal looks like.
  • Test your rate limiter under adversarial conditions deliberately. Send boundary burst requests at window transitions. Test from multiple source IPs simultaneously. Verify that IPv6 address variants are treated as the same identifier.

The Operational Reality

Rate limiting is not a set-and-forget control. Attackers adapt their request patterns when they encounter limits. Legitimate usage patterns change as your product evolves. The thresholds that were appropriate six months ago may be too permissive for today's threat environment or too restrictive for today's legitimate usage patterns.

Schedule rate limit configuration reviews on a quarterly cadence at minimum. Review them immediately after any incident where automated abuse contributed to a breach or service degradation. Treat rate limit telemetry as a first-class data source in your threat hunting workflow alongside firewall logs, authentication events, and endpoint telemetry.

The teams that consistently catch automated abuse before it causes meaningful damage share one characteristic: they treat their rate limiting infrastructure as a sensor that generates signal, not just a control that blocks traffic. The signal is there in the telemetry. The question is whether your monitoring pipeline is configured to surface it before the attack has already completed its objective.

Contact IPThreat