Skip to content

fix(app): bound Redis rate-limiter socket timeout#47

Merged
AlexanderWagnerDev merged 1 commit into
mainfrom
claude/bug-security-audit-nqtn2b
Jul 11, 2026
Merged

fix(app): bound Redis rate-limiter socket timeout#47
AlexanderWagnerDev merged 1 commit into
mainfrom
claude/bug-security-audit-nqtn2b

Conversation

@AlexanderWagnerDev

@AlexanderWagnerDev AlexanderWagnerDev commented Jul 11, 2026

Copy link
Copy Markdown
Contributor

Summary

Independent bug-scan pass focused on the new Redis-backed shared login rate limiter (38bc33f, 9fa5e83, 2860249, 4b19d6b), which landed after the last documented full-module scan (.cursor/bug-scan-progress.md, 2026-07-10) and hadn't had a manual review pass yet (only automated CodeRabbit/Codex review).

Verified against the actual Flask-Limiter==4.1.1 / limits==5.8.0 source (not from memory):

  • The limiter fails closed on a Redis outage — no login-limit bypass.
  • The Redis backend increments atomically via a Lua script — no cross-worker TOCTOU race.
  • Every /login request is counted before password comparison — no uncounted bypass path.

One real bug found and fixed:

  • Limiter(...) passed no storage_options, so the underlying redis.Redis client used redis-py's default None socket timeout. Since the limiter runs as a before_request hook for every route (not just /logindefault_limits=["100 per minute"] is global), a Redis instance that's up but not responding (network stall, overload) would hang every Gunicorn worker indefinitely on any request — a Redis-side stall becomes a full panel DoS. Fixed by adding storage_options={"socket_timeout": 2, "socket_connect_timeout": 2} (a no-op for the in-memory test backend, verified via limits' MemoryStorage.__init__ which accepts and ignores extra kwargs).

Other things reviewed and found sound (documented in .cursor/bug-scan-progress.md): fail-closed blast radius (whole panel, not just login, on Redis outage — an accepted tradeoff since an in-memory fallback would reopen the original multi-worker bypass this PR fixed), IP-only rate-limit keying (pre-existing, not a regression), Redis network exposure (internal-only, no host port mapping), and CSRF/rate-limit hook ordering (no bypass).

Test plan

  • pytest tests/ --ignore=tests/test_integration_server.py (58 passed)
  • pytest tests/test_login_routes.py tests/test_app.py specifically (48 passed, includes the rate-limiter tests)

Generated by Claude Code


View with Codesmith Autofix with Codesmith
Need help on this PR? Tag /codesmith with what you need. Autofix is disabled.

Summary by CodeRabbit

  • Bug Fixes

    • Prevented requests from hanging indefinitely when the rate-limiting service is unresponsive.
    • Added two-second connection and response timeouts for rate-limit checks, improving application responsiveness and availability.
  • Documentation

    • Updated the changelog with details of the rate-limiter timeout fix.

Limiter's storage_uri pointed at Redis with no socket_timeout /
socket_connect_timeout, so redis-py defaulted to blocking indefinitely.
Since the limiter runs as a before_request hook for every route (not
just /login), a Redis instance that's up but not responding (network
stall, overload) would hang every Gunicorn worker on any request --
turning a Redis-side stall into a full panel outage. Added a 2s
socket_timeout/socket_connect_timeout via storage_options (a no-op for
the in-memory test backend).

Found while independently reviewing the new shared Redis rate-limiter
added in 38bc33f/9fa5e83/2860249/4b19d6b; everything else checked
(fail-closed on Redis outage, atomic Lua-script increment, counting
before password comparison) held up.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U7XvmEneuMexTJGbvC1EQR
@coderabbitai

coderabbitai Bot commented Jul 11, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c899eadb-3825-4aed-a721-2d2f2547e8fd

📥 Commits

Reviewing files that changed from the base of the PR and between e30f0b6 and 59644f4.

📒 Files selected for processing (3)
  • .cursor/bug-scan-progress.md
  • CHANGELOG.md
  • app.py

📝 Walkthrough

Walkthrough

The Flask-Limiter configuration now sets two-second Redis socket and connection timeouts. The bug-scan progress document records the rate-limiter review and completed scan items, while the changelog documents the timeout change.

Changes

Redis limiter timeouts

Layer / File(s) Summary
Configure limiter timeouts
app.py, .cursor/bug-scan-progress.md, CHANGELOG.md
create_app() adds two-second socket_timeout and socket_connect_timeout storage options, with corresponding scan notes and an unreleased changelog entry.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely reflects the main change: adding Redis rate-limiter socket timeouts in app.py.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/bug-security-audit-nqtn2b

Comment @coderabbitai help to get the list of available commands.

@sonarqubecloud

Copy link
Copy Markdown

@AlexanderWagnerDev AlexanderWagnerDev merged commit 5c2efcb into main Jul 11, 2026
11 checks passed
@AlexanderWagnerDev AlexanderWagnerDev deleted the claude/bug-security-audit-nqtn2b branch July 11, 2026 16:33
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.

2 participants