Designing Rate Limiting That Holds When Attackers Already Know Your API Layout

By IPThreat Team July 3, 2026

A Production Failure That Should Have Been Preventable

In early 2026, a mid-sized financial services provider suffered a credential stuffing campaign that exhausted its authentication API for nearly four hours before the security team isolated the traffic pattern. The rate limiter was configured and running. The thresholds had been set during a planning session six months earlier, tuned against synthetic load tests, and never revisited. When the attack arrived, it distributed requests across 4,000 residential IP addresses, each staying comfortably below the per-IP limit. The rate limiter saw nothing alarming. The authentication service saw something close to catastrophic.

This scenario is not unusual. As the SANS ISC Stormcast and recent threat briefs on large-scale credential attacks have highlighted, distributed abuse of APIs has matured far beyond simple brute force. Attackers now map API surfaces carefully, probe for enforcement boundaries, and calibrate request volume to stay inside whatever limits defenders have published or accidentally revealed through error responses. The question for cybersecurity professionals and IT administrators is no longer whether to rate limit, but how to design rate limiting that accounts for adversaries who have already done their homework.

What Rate Limiting Is Actually Protecting Against

Rate limiting serves several distinct purposes that are worth separating before choosing a strategy. At the most basic level, it protects infrastructure availability by preventing any single client from monopolizing backend resources. At a security level, it degrades the economics of automated attacks by increasing the time and cost required to complete credential stuffing, enumeration, or scraping campaigns. At an operational level, it generates signals that, when properly logged and analyzed, reveal attack patterns early enough to trigger a meaningful response.

The challenge is that these goals sometimes require different configurations. A limit designed to protect infrastructure might be set high enough that a distributed credential stuffing campaign slides under it indefinitely. A limit tuned tightly enough to disrupt distributed attacks might generate enough false positives to create friction for legitimate users. Getting this balance right requires understanding the specific threat model for each API endpoint, not applying a single policy across the entire surface.

The Core Algorithms and Their Real Tradeoffs

Fixed Window Counting

Fixed window rate limiting counts requests within discrete time windows, typically reset every minute or every hour. Implementation is straightforward: increment a counter per identifier, compare against a threshold, reject when the threshold is exceeded, and reset the counter when the window expires.

The practical weakness of fixed windows is the boundary condition. An attacker who understands the reset timing can send requests in two bursts: one at the end of a window and one immediately after reset. This produces up to twice the allowed volume in a short span without triggering limits in either window. For low-sensitivity endpoints this tradeoff is acceptable. For authentication endpoints or any API accepting credentials, fixed windows are a poor choice as the primary mechanism.

Sliding Window Logs

Sliding window log rate limiting maintains a timestamped record of each request and calculates the count within a rolling window ending at the current moment. This eliminates the boundary condition problem. If the limit is 100 requests per minute, it means exactly 100 requests in any 60-second span, regardless of when that span starts.

The cost is memory. Storing a timestamp for every request from every tracked identifier becomes expensive at scale. For high-traffic APIs this approach requires careful consideration of the storage backend. Redis sorted sets are a common implementation choice because they allow efficient range queries by timestamp and automatic expiration. A sorted set keyed by identifier holds timestamps as members with the timestamp as the score, allowing range-based deletion and count in a single pipeline.

Sliding Window Counters

Sliding window counters approximate the sliding window log approach by combining two fixed window counts with a weighted calculation. The current window count is added to the previous window count multiplied by the fraction of the previous window still within the rolling period. This reduces memory consumption significantly while producing results that are accurate enough for most rate limiting purposes.

The approximation introduces some tolerance for burst behavior at window boundaries, but for most security applications this tolerance is small enough to be acceptable. This is the approach used by many high-traffic platforms because it scales without the memory overhead of full log-based sliding windows.

Token Bucket

Token bucket rate limiting models capacity as a bucket that refills at a fixed rate up to a maximum. Each request consumes one or more tokens. When the bucket empties, requests are rejected until tokens accumulate again. The key characteristic is that it permits short bursts up to the bucket capacity while enforcing a sustained throughput limit equal to the refill rate.

For APIs where legitimate users sometimes send rapid sequences of requests followed by quiet periods, token bucket behavior matches real usage patterns well. For authentication endpoints where burst tolerance creates an exploitable window, the bucket maximum should be kept small relative to the refill rate.

Leaky Bucket

Leaky bucket rate limiting enforces a strictly uniform output rate regardless of input burst patterns. Incoming requests queue if the processing rate is not exceeded, and the queue drains at a fixed rate. Requests that arrive when the queue is full are rejected. This produces the smoothest possible traffic shape but introduces latency for legitimate users during busy periods and provides no burst allowance.

Leaky bucket is most useful for protecting backend systems with strict processing capacity limits. It is less suited as a primary security control for external-facing APIs because it does not directly limit how many requests a given client can make over time, only how quickly the system processes them.

Choosing the Right Identifier

Every rate limiting strategy depends on a key that identifies the client being limited. Choosing the wrong identifier is one of the most common ways rate limiting fails in practice.

IP address is the default choice and the most easily defeated. As recent threat intelligence reporting on large-scale credential attacks confirms, modern attack infrastructure uses residential proxy networks and botnet-compromised endpoints to distribute requests across tens of thousands of distinct IP addresses. A rate limiter keyed only on IP will see each address make a handful of requests and conclude everything is normal.

User account or username is a more durable key for authentication endpoints. Limiting the number of authentication attempts per account, regardless of source IP, directly disrupts credential stuffing regardless of how widely the attack distributes its source addresses. The tradeoff is that this approach opens a denial-of-service vector: an attacker can deliberately lock out legitimate user accounts by generating failed authentication attempts at a controlled rate below the lockout threshold but above what triggers account lockout. Careful threshold design and lockout behavior that degrades gracefully rather than hard-locking accounts mitigates this.

API key or session token is appropriate for authenticated API endpoints. Limiting by authenticated identity ensures that a compromised account cannot be used to hammer downstream services regardless of the IP it originates from.

Device fingerprint combines multiple request characteristics, including TLS fingerprint, HTTP header ordering, user agent, and timing patterns, to produce an identifier that persists even when the IP address changes. This approach is more complex to implement and maintain, but it significantly raises the cost of evasion for automated clients. Libraries and services implementing JA3 or JA4 TLS fingerprinting are a practical starting point for this layer.

For high-risk endpoints, layering multiple identifier types produces the most robust coverage. An authentication endpoint might enforce limits per IP as a fast-path check, per username as a secondary check, and per device fingerprint as a behavioral check, with any limit triggering protective action.

Designing for the Distributed Attack Case

Distributed attacks that stay below per-IP limits while accumulating significant total volume require aggregate rate limiting to detect and respond to. Rather than only tracking per-identifier counts, aggregate rate limiting tracks the total request volume hitting a specific endpoint across all clients within a window.

When the aggregate rate exceeds a defined threshold, the response should not be to blindly block all traffic. A more effective approach is to trigger secondary analysis. This might mean shifting from a permissive mode to a challenge mode, where clients that have not previously solved a challenge receive one before proceeding. It might mean increasing scrutiny of requests, routing them through additional validation logic, or generating alerts that feed into active investigation.

Aggregate thresholds require careful calibration against baseline traffic. For a login endpoint that normally receives 500 requests per minute during peak hours, a threshold of 2,000 requests per minute would catch an attack that triples normal volume. Setting this threshold requires observing real traffic patterns over time, which means logging needs to be in place before an attack arrives rather than after.

Implementing Graduated Responses Instead of Binary Blocks

Binary rate limiting, where a client either passes or gets a 429 response, is the simplest implementation and the one that leaks the most information to an attacker. A client that receives consistent 429 responses knows exactly where the limit sits and can calibrate precisely below it.

Graduated responses introduce uncertainty that makes calibration harder. Rather than immediately returning 429 on threshold breach, a graduated system might first introduce artificial delay, then present a challenge, then return 429, with each stage triggered at different thresholds. This approach, sometimes called a speed bump or soft block, disrupts automated tooling that expects consistent response patterns without creating the same abrupt friction for legitimate users who occasionally exceed limits.

Returning 429 responses with Retry-After headers that reflect the true reset time also gives attackers precise timing information. Consider returning Retry-After values that are slightly longer than the actual reset, or that vary within a range. This does not meaningfully affect legitimate clients but complicates the timing calculations that automated attack tools rely on.

Rate Limiting in a Distributed Architecture

Rate limiting that lives inside a single application server does not scale horizontally. When load balancers distribute traffic across multiple instances, each instance sees only its fraction of the total request volume. A client sending 1,000 requests per minute spread evenly across 10 instances would appear to each instance as 100 requests per minute, defeating any per-instance limit set below that.

Centralized rate limiting requires a shared state store. Redis is the most common choice because of its atomic increment operations, built-in expiration, and low latency. The INCR and EXPIRE commands, combined with Lua scripting for atomic check-and-increment operations, provide the building blocks for all the algorithms described above. A Redis cluster with appropriate persistence configuration handles the throughput and availability requirements of most production API deployments.

Cloud-native alternatives include managed rate limiting services offered by API gateway products from major cloud providers. AWS API Gateway, Azure API Management, and Google Cloud Apigee all offer built-in rate limiting with quota management. The advantage is reduced operational overhead. The limitation is that the configuration options may be less flexible than a custom implementation, and the rate limiting logic is further from the application, which can complicate fine-grained behavioral responses.

Reverse proxies and CDN layers provide another enforcement point. Cloudflare, Fastly, and similar providers offer rate limiting rules that can be applied before traffic reaches origin infrastructure. This protects origin servers even during high-volume attacks and can leverage the provider's visibility across their entire customer base for threat intelligence enrichment. The tradeoff is that enforcement at this layer is less context-aware: the CDN sees request headers and URLs but not application-layer context like whether authentication succeeded or failed.

What Good Logging Looks Like for Rate Limiting Events

Rate limiting that does not generate useful logs is a control that cannot be evaluated, tuned, or used as a detection signal. Every rate limit event should produce a log record that includes the timestamp, the identifier that triggered the limit, the endpoint, the request count at time of limit, the action taken, and the source IP even when the primary identifier is something else.

These logs need to feed into the same analysis pipeline as other security events. A sudden increase in rate limit events across multiple identifiers targeting the same endpoint is a signal that an attack is distributing across identifiers to evade per-identifier limits. This pattern is detectable with aggregate analysis that security teams can implement in their SIEM, but only if the log volume and structure support it.

Correlating rate limit events with authentication failure events is particularly valuable. The recent SANS Threat Brief on large-scale credential attacks highlights that sophisticated campaigns often maintain a low per-source failure rate precisely to avoid triggering both rate limits and account lockout policies simultaneously. An authentication endpoint might see 10,000 failed attempts from 3,000 IP addresses over two hours, with each IP failing twice and triggering no individual limits. The correlation across all of those events is what reveals the campaign.

Protecting Non-Authentication Endpoints That Attackers Also Target

Authentication endpoints receive the most attention in rate limiting discussions, but several other endpoint categories carry significant risk from abuse that rate limiting can address.

Account registration endpoints are attractive targets for bot-driven account creation, which feeds downstream fraud and spam campaigns. Rate limiting registration by IP, device fingerprint, and email domain (particularly disposable email domains) significantly raises the cost of large-scale account creation.

Password reset and account recovery endpoints are high-value targets for account takeover campaigns. The SANS ISC discussion of secret codes and credential bypass scenarios from July 2026 points to exactly this dynamic: attackers who cannot brute-force the primary authentication path look for alternatives in recovery flows. Rate limiting these endpoints more aggressively than primary login, and requiring proof of identity before initiating recovery, closes a common bypass route.

Data retrieval and search endpoints are targets for scraping campaigns that extract sensitive data at scale. Rate limiting by authenticated identity combined with anomaly detection on access patterns, specifically looking for systematic traversal of records or unusually high volumes of unique object accesses, can surface scraping behavior that stays below simple request rate limits.

The ToddyCat campaign analysis published in mid-2026, which described threat actors using email access as an intelligence-gathering mechanism, illustrates how API access to data endpoints can be weaponized for long-running collection operations. These operations often stay well below rate limits because the attacker is not in a hurry; they are conducting persistent access over weeks. This is where behavioral analysis of access patterns over longer windows, days rather than minutes, complements traditional rate limiting.

Testing Rate Limiting Before Attackers Do

Rate limiting configurations that have never been tested under adversarial conditions frequently fail in ways that are only discovered during an actual incident. Structured testing before deployment is the most reliable way to validate that the implementation matches the design intent.

Testing should verify that limits apply correctly for each identifier type, that distributed requests across multiple identifiers do not aggregate above the intended ceiling at the endpoint level, that graduated responses trigger at the expected thresholds, that the shared state store handles the expected peak load without becoming a bottleneck, and that the logging output contains all required fields in a consistent format.

Red team exercises that specifically target rate limiting as a control, rather than treating it as background infrastructure, produce the most actionable findings. A red team tasked with bypassing rate limiting will quickly discover whether the per-IP limit is the only enforcement layer, whether the Retry-After header reveals timing information that enables precise calibration, and whether backend services that the rate limiter is protecting can be reached through any path that bypasses enforcement.

For organizations without internal red team capability, tooling like Locust, k6, or custom scripts that distribute requests across proxied IP addresses can validate basic enforcement behavior. These tests are not a substitute for adversarial testing but catch the most common configuration errors before they matter.

Maintaining Rate Limiting as Threat Patterns Evolve

Rate limiting configurations set during initial deployment and never revisited create the same class of problem as unpatched software. Attack techniques evolve, traffic patterns change as the application evolves, and thresholds calibrated against historical baselines become inaccurate as usage grows.

A practical maintenance cadence for high-risk endpoints includes reviewing rate limit event volumes monthly to identify trends, revisiting threshold configurations quarterly against updated traffic baselines, and updating identifier strategies when new attack techniques emerge that defeat current controls. The SMB cyber readiness guidance published in mid-2026 makes the point that security controls need ongoing maintenance budgets, not just initial deployment effort. Rate limiting is a clear example of a control where the ongoing maintenance cost is low but the consequence of skipping it compounds over time.

Threat intelligence feeds that include information about current attack tooling and techniques can inform threshold and strategy adjustments. If intelligence reporting describes a shift toward credential stuffing tools that distribute across larger numbers of residential proxies, that is a signal to lower per-IP thresholds or increase the weight of aggregate endpoint-level limits. Acting on that signal before the attack arrives is considerably less painful than acting on it after.

Practical Starting Configuration for Authentication Endpoints

For teams looking for a concrete starting point rather than only principles, the following configuration represents a reasonable baseline for a public-facing authentication endpoint. It should be adjusted based on observed traffic patterns and specific risk tolerance.

  • Per-IP limit: 10 authentication attempts per 10-minute sliding window, with a soft block at 7 that introduces a 2-second artificial delay before responding
  • Per-username limit: 20 authentication attempts per hour, with account flagging at 10 failed attempts for manual review, and no hard lockout that enables denial-of-service
  • Aggregate endpoint limit: 5x the 30-day peak hourly authentication volume as a trigger for elevated alerting and optional challenge mode activation
  • Device fingerprint limit: 50 authentication attempts per 24-hour period per fingerprint, applied independently of IP-based limits
  • Retry-After header: return a value between 60 and 120 seconds (randomized) rather than the exact reset time
  • Logging: every limit event logged with identifier type, identifier value, endpoint, request count, action taken, and source IP

This configuration alone does not make authentication secure. It is one layer in a stack that should also include multi-factor authentication, credential breach monitoring, behavioral anomaly detection, and incident response procedures calibrated to authentication-related alerts. Rate limiting that generates no response process when it triggers provides less actual protection than its presence implies.

Closing Thoughts

Rate limiting is a control that most teams have deployed in some form and most teams have not validated thoroughly enough to rely on during an actual attack. The gap between a rate limiter that exists and one that holds under adversarial conditions is almost always a design and testing problem rather than a tooling problem. The algorithms are well understood, the implementations are mature, and the failure modes are documented.

What separates teams that catch distributed credential attacks early from teams that read about the breach in their logs is the decision to treat rate limiting as a living control: one that gets tested, tuned, and reviewed on a schedule rather than deployed and forgotten. Given the volume and sophistication of credential attack campaigns active today, that decision is straightforward to justify and straightforward to act on.

Contact IPThreat