Skip to content

fix: add brute-force and rate-limit protection to login endpoints#515

Open
JavaProgswing wants to merge 1 commit into
Eswaramuthu:mainfrom
JavaProgswing:fix/login-rate-limit-protection
Open

fix: add brute-force and rate-limit protection to login endpoints#515
JavaProgswing wants to merge 1 commit into
Eswaramuthu:mainfrom
JavaProgswing:fix/login-rate-limit-protection

Conversation

@JavaProgswing
Copy link
Copy Markdown

Fixes #497

@vercel
Copy link
Copy Markdown

vercel Bot commented Jun 2, 2026

@JavaProgswing is attempting to deploy a commit to the 007's projects Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 2, 2026

Thanks for creating a PR for your Issue! ☺️

We'll review it as soon as possible.
In the meantime, please double-check the file changes and ensure that all commits are accurate.

If there are any unresolved review comments, feel free to resolve them. 🙌🏼

Comment thread app.py
get_remote_address,
app=app,
default_limits=["200 per day", "50 per hour"],
storage_uri="memory://"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAJOR SECURITY In-memory rate-limit storage bypassed under multi-worker deployments

storage_uri="memory://" gives each gunicorn worker an independent counter, so an attacker gets 5 login attempts per worker rather than 5 total — effectively defeating the brute-force protection this PR was added to provide.

Suggested change
storage_uri="memory://"
storage_uri=os.environ.get("RATELIMIT_STORAGE_URI", "memory://")
Prompt to fix with AI

Copy this prompt into your AI coding assistant to fix this issue.

In app.py at line 37, `storage_uri="memory://"` causes each gunicorn worker to maintain independent rate-limit counters, so the 5 POST/15min brute-force limit is multiplied by the number of workers. Fix: change line 37 to `storage_uri=os.environ.get("RATELIMIT_STORAGE_URI", "memory://")` and configure a Redis URI (e.g. `redis://localhost:6379`) in the environment for production deployments. This ensures all workers share one counter.

Comment thread app.py

@app.errorhandler(429)
def ratelimit_handler(e):
return render_template("404.html", error_message=f"Too many requests. {e.description}"), 429
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MAJOR BUG Rate-limit error message is never displayed to users

404.html has no {{ error_message }} variable — it renders hardcoded '404 Page Not Found' text regardless of what's passed. Users hitting the rate limit see a misleading 404 page, and the custom rate-limit message is silently dropped.

@entelligence-ai-pr-reviews
Copy link
Copy Markdown
Contributor


Confidence Score: 2/5 - Changes Needed

Not safe to merge — while this PR takes a meaningful step toward brute-force and rate-limit protection on login endpoints, two significant issues undermine its effectiveness in production. The use of storage_uri="memory://" means each gunicorn worker maintains an independent counter, allowing attackers to trivially bypass rate-limiting by distributing requests across workers — the protection simply does not work in any standard multi-worker deployment. Additionally, the rate-limit error response renders 404.html, which contains no {{ error_message }} template variable, so users (and defenders) receive a generic '404 Page Not Found' page with no indication that they've been rate-limited, masking the feature entirely.

Key Findings:

  • storage_uri="memory://" in app.py is incompatible with multi-worker deployments (e.g., gunicorn with multiple workers): each worker holds its own isolated counter, so an attacker can send N requests per worker before being blocked, multiplying the effective rate limit by the worker count and rendering the protection useless in production.
  • The rate-limit error handler points to 404.html, which has no {{ error_message }} placeholder — the intended user-facing error message is silently dropped, users see a misleading '404 Page Not Found' response, and the rate-limiting behavior is invisible both to end-users and to any monitoring that might key on HTTP 429 semantics.
  • The PR's intent is sound — adding brute-force and rate-limit protection to login endpoints is the right security control — but both identified issues are load-bearing: one breaks the feature under real deployment conditions and the other breaks the feedback loop entirely.
Files requiring special attention
  • app.py

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

BUG - [Security][Backend] Login endpoints accept unlimited attempts with no brute-force / rate-limit protection

1 participant