Quick answer
Rate limiting is often applied poorly: sometimes only on one of several equivalent endpoints, sometimes based on spoofable headers, sometimes only by IP when X-Forwarded-For is accepted. Bypassing it enables OTP brute force, password guessing, mass enumeration, and it's often the missing piece to escalate low-impact findings to critical.
Bypass patterns
1. Spoofable X-Forwarded-For header
Apps behind a CDN/proxy trust X-Forwarded-For to identify the client's IP. If the rate limiter uses this header without validation:
POST /login HTTP/1.1
Host: target.tld
X-Forwarded-For: 1.1.1.1
Each request with a different value "looks like" a different IP:
for i in $(seq 1 1000); do
curl -H "X-Forwarded-For: $((RANDOM%255)).$((RANDOM%255)).$((RANDOM%255)).$((RANDOM%255))" \
-d 'user=admin&pass=guess' https://target.tld/login
done
Common headers to try:
X-Forwarded-For
X-Real-IP
X-Originating-IP
X-Remote-IP
X-Remote-Addr
X-Client-IP
X-Forwarded
Forwarded-For
True-Client-IP (Cloudflare/Akamai)
CF-Connecting-IP (Cloudflare)
Fastly-Client-IP
X-Cluster-Client-IP
Via
2. Real IP rotation (without headers)
If the rate limit is by real IP:
- AWS Lambda from your own script: each invocation can go out from a different IP depending on the runtime. Free tier is enough.
- Cloud functions (GCP, Vercel, Netlify) — your own function calling the target.
- Tor circuits — a new circuit every N requests.
- List of public proxies (legal, residential or paid datacenter).
- Cloudfront IPs if the app is behind Cloudfront — bypass with
Host: target.tldfrom another Cloudfront IP.
3. Path casing and encoding
Some rate limiters index by exact path:
/login (limited)
/Login (NOT limited)
/LOGIN
/log%69n (URL-encoded letter)
/login/
/login//
/login;a=1 (path parameters ignorados)
/login?x=1 (query string)
/login#a
/login%20 (trailing space)
If the server normalizes the path before processing but the rate limiter doesn't, bypass.
4. Equivalent endpoints
Large apps frequently have several endpoints that do the same thing:
/api/v1/loginand/api/v2/login./loginand/auth/login./api/loginand/api/internal/login./loginand/oauth/token(password grant).- Mobile API (
/mobile/api/...) vs web API. - GraphQL endpoint mapping to the same backend.
If only /login has a rate limit but /api/v1/login or the GraphQL mutation login doesn't → bypass.
5. Race condition with rate limit buckets
Some rate limiters reset in windows: 5 attempts per 5 minutes.
- If timestamping is by exact-hour bucket (60min), try right at the bucket change: 50 attempts at 11:59:30 + 50 at 12:00:30.
- Some reset on a successful login → if you have a valid account, you can alternate it with guesses against the victim's to reset the counter.
6. HTTP smuggling to evade the WAF/proxy
The CDN/proxy applies the rate limit. The backend server doesn't. If there's HTTP smuggling, a request slips through to the backend without going through the proxy's rate limiter. (See the dedicated article on HTTP request smuggling.)
7. WebSocket fallback
Some endpoints have a REST version and a WebSocket version. If only REST is rate-limited, the WebSocket processes thousands of messages per connection without throttling.
8. GraphQL aliasing
A single GraphQL request can run the same mutation N times:
mutation {
attempt1: login(user: "victim", pass: "guess1") { token }
attempt2: login(user: "victim", pass: "guess2") { token }
...
attempt100: login(user: "victim", pass: "guess100") { token }
}
If the rate limit counts HTTP requests but not operations within each request, 1 request = 100 attempts. Total bypass.
9. Bucket reset by user input
Common pattern: rate limit by (IP, username). If the attacker varies the username:
victim@email.tld
Victim@email.tld (case → mismo user en algunos backends, distinto bucket en rate limiter)
victim@Email.TLD
victim+x@email.tld
Real case: the 0-click-ato-otp-brute-force bug documented in another Academy article.
10. Cookie-based identification bypass
If the rate limit uses a cookie/session:
- Clearing cookies between requests → direct bypass.
- Creating mass anonymous accounts and rotating.
Quick detection
Burp Repeater + Intruder with 100 fast requests. Measure:
- Does the status code change? (200 → 429 → ?).
- After how many requests?
- Does it reset per minute, per hour, per day?
- By IP, by user, by session?
Once the mechanism is identified, try the corresponding bypasses.
Frequent impact cases
- OTP brute force on password reset → mass ATO.
- Login brute force on accounts with weak passwords.
- Email enumeration without throttling → list of valid accounts.
- API keys generation flood → DoS / abuse of free quota.
- Coupon code brute → stolen discount codes.
- Phone number enumeration via "send OTP" endpoints.
Hunting checklist
- Does the rate limiter respond 429 after X requests? Measure it.
- Does an arbitrary
X-Forwarded-Forbypass it? - Does path capitalization bypass it?
- Are there equivalent endpoints without a rate limit?
- Does GraphQL allow aliasing of the same mutation?
- WebSocket version of the endpoint?
- Does email casing affect the bucket but not the real auth?
- Can cookies be rotated to reset it?
- Does an "internal" API on another path process the same backend?
Correct mitigation
- Rate limit by real IP (validated by a trusted proxy, not spoofable via an arbitrary header).
- Rate limit by user account (not just IP) when there's an identifiable user.
- Shared bucket across all equivalent endpoints.
- Counting of operations within each request (matters especially in GraphQL).
- Temporary lockout after N consecutive failed attempts on the same account.
Related labs
Practice IP rotation, header spoof, GraphQL aliasing and rate limit race condition: Rate Limiting labs.
Practice this in a lab
Rate Limiting
Keep learning · free account
Save your progress, unlock advanced payloads and rank your flags.
Related articles
0-click Account Takeover — OTP brute force + Email Normalization
Two separate flaws look minor. Together, they hand you full ATO knowing only the email. Real bounty: €560 and 12 minutes of exploitation.
Mass PII Extraction via GraphQL — 93 real profiles in 1 hour
A contact-sync GraphQL endpoint with no rate limiting, no ownership verification and batching of 200 numbers per request. Phone → real identity resolution.
SSRF — complete bypasses: localhost, IPv6, decimal, DNS and cloud metadata
11 techniques to bypass SSRF validation: enclosed alphanumeric, decimal IP, dot bypass, DNS rebinding, parameter pollution. Cloud metadata AWS/GCP/Azure.