skills/igbuend/grimbard/missing-rate-limiting-anti-pattern

missing-rate-limiting-anti-pattern

SKILL.md

Missing Rate Limiting Anti-Pattern

Severity: High

Summary

Applications fail to restrict action frequency, allowing unlimited requests to endpoints. Enables brute-force attacks, data scraping, and denial-of-service through resource-intensive requests.

The Anti-Pattern

The anti-pattern is exposing endpoints (especially authentication/resource-intensive) without controlling request frequency per user or IP.

BAD Code Example

# VULNERABLE: The login endpoint has no rate limiting.
from flask import request, jsonify

@app.route("/api/login", methods=["POST"])
def login():
    username = request.form.get("username")
    password = request.form.get("password")

    # Endpoint callable thousands of times per minute from same IP.
    # Attacker uses password lists for brute-force/credential stuffing,
    # trying millions of passwords until finding correct one.
    if check_credentials(username, password):
        return jsonify({"status": "success", "token": generate_token(username)})
    else:
        return jsonify({"status": "failed"}), 401

# Search endpoint without rate limiting.
@app.route("/api/search")
def search():
    query = request.args.get("q")
    # Attacker rapidly hits endpoint, scraping data or causing
    # DoS through heavy database work.
    results = perform_complex_search(query)
    return jsonify(results)

GOOD Code Example

# SECURE: Implement rate limiting using middleware and a tracking backend like Redis.
from flask import request, jsonify
from redis import Redis
from functools import wraps

redis = Redis()

def rate_limit(limit, per, scope_func):
    def decorator(f):
        @wraps(f)
        def decorated_function(*args, **kwargs):
            key = f"rate-limit:{scope_func(request)}:{request.endpoint}"
            # Increment count for current key.
            # Expire after `per` seconds on first request in window.
            p = redis.pipeline()
            p.incr(key)
            p.expire(key, per)
            count = p.execute()[0]

            if count > limit:
                return jsonify({"error": "Rate limit exceeded"}), 429

            return f(*args, **kwargs)
        return decorated_function
    return decorator

# Get identifier for rate limit scope (IP address).
def get_ip(request):
    return request.remote_addr

# Apply different rate limits per endpoint.
@app.route("/api/login", methods=["POST"])
@rate_limit(limit=10, per=60*5, scope_func=get_ip) # 10 requests/5min per IP
def login_secure():
    # ... login logic ...
    pass

@app.route("/api/search")
@rate_limit(limit=100, per=60, scope_func=get_ip) # 100 requests/min per IP
def search_secure():
    # ... search logic ...
    pass

Detection

  • Review public endpoints: Examine all endpoints that can be accessed without authentication. Do they have rate limiting?
  • Check authentication endpoints: Specifically look at login, password reset, and registration endpoints. These are prime targets for brute-force attacks if not rate-limited.
  • Analyze API design: For public APIs, check if there is a documented rate-limiting policy (e.g., in the API documentation).
  • Perform testing: Write a simple script to hit a single endpoint in a tight loop. If you don't receive a 429 Too Many Requests status code after a certain number of attempts, the endpoint is likely missing rate limiting.

Prevention

  • Implement IP-based rate limiting: All public endpoints, especially authentication/sensitive ones.
  • Implement account-based rate limiting: Prevent authenticated users from abusing system.
  • Use appropriate algorithm: Token Bucket, Leaky Bucket, or Fixed/Sliding Window. Most frameworks have middleware.
  • Return 429 Too Many Requests: Include Retry-After header indicating retry time.
  • Log rate limit violations: Identify and respond to potential attacks.
  • Consider account lockouts for login: Additional defense after failed attempts.

Related Security Patterns & Anti-Patterns

References

Weekly Installs
4
GitHub Stars
4
First Seen
Jan 20, 2026
Installed on
claude-code4
codex4
cursor4
opencode4
trae-cn3
antigravity3