Weakness reference
CWE-799

Improper Control of Interaction Frequency

This weakness occurs when software fails to limit how often a user or automated system can perform a specific action—such as submitting a login attempt…

01Summary

This weakness occurs when software fails to limit how often a user or automated system can perform a specific action—such as submitting a login attempt, posting a comment, or requesting a resource. Without these controls, attackers can abuse the system at scale: brute-forcing passwords, flooding the server, scraping data, or triggering expensive operations repeatedly. Proper rate limiting is a foundational defense against automation-driven attacks.

02How It Happens

Applications often process user requests without tracking or restricting how many times the same actor can perform an action within a given time window. This can happen because:

- No rate-limiting logic exists
— the code accepts every request without checking frequency. - Limits are too loose
— thresholds are set so high they offer no real protection. - Tracking is per-IP only
— attackers using distributed sources or proxies bypass the check. - No persistent state
— the application doesn't remember previous attempts across requests or sessions. - Limits apply globally, not per-user
— one attacker's requests count against all users' quotas.

The result is that an attacker can automate requests at machine speed, turning what should be a manual, human-paced action into a bulk operation.

03Real-World Impact

Unrestricted interaction frequency enables several attack classes:

- Credential brute-forcing:
An attacker can try thousands of password combinations against a login endpoint in minutes. - Account enumeration:
Repeated requests to a password-reset or user-lookup endpoint reveal which accounts exist. - Denial of service:
Flooding an endpoint with requests exhausts server resources, making the service unavailable to legitimate users. - Data scraping and exfiltration:
An attacker can systematically download large volumes of data by making repeated requests. - Abuse of expensive operations:
Triggering resource-intensive actions (file uploads, report generation, API calls) repeatedly can incur costs or degrade performance.

04Vulnerable & Fixed Patterns

Vulnerable pattern
from flask import Flask, request

app = Flask(__name__)

@app.route('/login', methods=['POST'])
def login():
    username = request.form.get('username')
    password = request.form.get('password')
    
    # No rate limiting — any IP can attempt login as many times as desired
    user = authenticate(username, password)
    if user:
        return "Login successful"
    else:
        return "Invalid credentials", 401

Why it's vulnerable:
Every request is processed immediately without checking how many login attempts have been made from this source in the recent past. An attacker can submit hundreds of guesses per second.

Fixed pattern
from flask import Flask, request
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address

app = Flask(__name__)
limiter = Limiter(app, key_func=get_remote_address)

@app.route('/login', methods=['POST'])
@limiter.limit("5 per minute")
def login():
    username = request.form.get('username')
    password = request.form.get('password')
    
    user = authenticate(username, password)
    if user:
        return "Login successful"
    else:
        return "Invalid credentials", 401
Vulnerable pattern
<?php
// No rate limiting on password reset requests
if ($_POST['action'] === 'reset_password') {
    $email = $_POST['email'];
    
    // Send reset link to any email, any number of times
    send_password_reset_email($email);
    echo "Reset link sent";
}
?>

Why it's vulnerable:
The endpoint accepts unlimited password-reset requests from the same IP or user, allowing attackers to spam inboxes or enumerate valid email addresses.

Fixed pattern
<?php
// Rate limiting using a simple in-memory or cache-based approach
if ($_POST['action'] === 'reset_password') {
    $email = $_POST['email'];
    $ip = $_SERVER['REMOTE_ADDR'];
    $cache_key = "reset_attempt_{$ip}";
    
    // Check if this IP has already requested a reset in the last 5 minutes
    $last_attempt = get_cache($cache_key);
    if ($last_attempt && (time() - $last_attempt) < 300) {
        http_response_code(429);
        echo "Too many reset requests. Try again later.";
        return;
    }
    
    send_password_reset_email($email);
    set_cache($cache_key, time());
    echo "Reset link sent";
}
?>

05Prevention Checklist

Implement rate limiting on sensitive endpoints
— login, password reset, API endpoints, file uploads, and any action that is expensive or abusable. Use a standard library or middleware (e.g., Flask-Limiter, WordPress plugins, nginx rate_limit module).
Track attempts per user and per IP
— don't rely on IP alone (proxies and botnets bypass it); also don't rely on user ID alone (enumeration attacks don't require valid accounts). Use both where possible.
Set realistic thresholds
— allow legitimate users to retry after mistakes, but block obvious automation. For login, 5–10 attempts per minute per IP is typical; adjust based on your user base.
Return appropriate HTTP status codes
— use 429 (Too Many Requests) when a limit is exceeded, so clients and monitoring tools recognize the condition.
Log and alert on repeated violations
— monitor for patterns of abuse and escalate to security or ops teams.
Consider CAPTCHA or multi-factor authentication
— for high-value endpoints, add a second barrier after a few failed attempts.

06Signs You May Already Be Affected

- Unusual login failure logs:
A spike in failed login attempts from a single IP or across many IPs in a short time window. - Unexpected password-reset emails:
Users report receiving many reset emails they didn't request, or your email provider flags your domain for spam. - Server resource exhaustion:
CPU, memory, or bandwidth spikes correlating with requests to a specific endpoint, without corresponding legitimate traffic. - Enumeration patterns in logs:
Requests to endpoints like /api/user/{id} or /password-reset?email=... with sequential or dictionary-like parameters.

07Related Recent Vulnerabilities