Skip to content

fix(security): rate-limit fail-open hardening — metric, degraded header, configurable fail-closed (OBS-1) - #106

Open
SabaTech-dev wants to merge 1 commit into
mainfrom
fix/rate-limit-fail-open
Open

fix(security): rate-limit fail-open hardening — metric, degraded header, configurable fail-closed (OBS-1)#106
SabaTech-dev wants to merge 1 commit into
mainfrom
fix/rate-limit-fail-open

Conversation

@SabaTech-dev

Copy link
Copy Markdown
Owner

Summary

Security audit OBS-1 (qa-visual-fase-c-pr105-2026-08-23.md): RateLimitMiddleware failed OPEN silently — if redis fails (test evidence: Rate limit check failed error='Event loop is closed'), requests proceeded with no rate limit and no signal. Applies app-wide (preexisting, not from PR #105). Relevant for cost abuse of paid endpoints (qa-visual analyze) once enabled.

Card: 4f9fb443 [P3].

Changes

Failures are now never silent:

  • Prometheus counter rate_limit_backend_failures_total{fail_mode} — incremented on every backing-store failure, exposed via the existing /metrics mount (alertable: increase(rate_limit_backend_failures_total[5m]) > 0).
  • Distinct log event rate_limit_backend_failure (error level, structlog) with fail_mode, error_type, key — replaces the generic message.
  • X-RateLimit-Mode: degraded response header in open mode — externally visible.

Configurable failure mode — env RATE_LIMIT_FAIL_MODE=open|closed (default open, backward compatible):

  • open: allow (as today) but flagged everywhere as above.
  • closed: deny with 503 + Retry-After while the backing store is down. A redis outage is service degradation, not client abuse — hence 503, not 429.
  • Invalid values fall back to open with a warning.
  • check_rate_limit dependency updated consistently (503 on degraded denial).

Hygiene:

  • Short-circuit on first backing-store failure → exactly one metric/log event per request (not 3, one per limit bucket).
  • Backend error strings stay server-side only — no leakage in responses/headers (S-3 discipline).

Testing

  • 8 new tests (TestFailModeBehavior): open marks degraded, closed denies, single-event short-circuit, metric increment per mode (via REGISTRY.get_sample_value), invalid mode fallback, middleware 200+header (open), middleware 503+Retry-After+no-leak (closed).
  • Updated test_redis_failure_fails_open: asserts degraded marker + absence of error in info.
  • tests/middleware/test_rate_limit.py 27/27, tests/middleware/ + test_qa_visual_wiring.py 50/50 — no regressions.

Deployment notes

  • Default behavior unchanged (fail open) — zero-config safe merge. Set RATE_LIMIT_FAIL_MODE=closed at deploy time if strict enforcement is desired (trade-off: redis outage → dashboard 503s).
  • Follow-up (out of scope): alertmanager rule on the new counter.

…er, configurable fail-closed

Security audit OBS-1 (PR #105, 2026-08-23): if redis fails, RateLimitMiddleware
failed OPEN silently — rate limiting disappeared without any signal.

- Prometheus counter rate_limit_backend_failures_total{fail_mode} on every
  backing-store failure (exposed via existing /metrics mount)
- Distinct structured log event rate_limit_backend_failure (server-side only)
- RATE_LIMIT_FAIL_MODE=open|closed env (default open, backward compatible);
  closed returns 503 + Retry-After (service degradation, not 429 abuse signal)
- X-RateLimit-Mode: degraded response header in open mode
- Short-circuit on first backing-store failure: one event per request
- No backend error strings in responses (S-3 discipline)
- check_rate_limit dependency: 503 on degraded denial

Tests: 8 new in TestFailModeBehavior + updated fails-open test. 27/27
test_rate_limit.py, 50/50 middleware+qa_visual_wiring.
@github-actions

Copy link
Copy Markdown

PR Check Results

Code Formatting: Failed
Linting: Failed
Type Checking: Failed
Tests: Failed

⚠️ Some checks failed. Please review the details above.

@github-actions

Copy link
Copy Markdown

❌ FAIL Trivy Security Scan Results

Severity Count
🔴 CRITICAL 4
🟠 HIGH 61
Total 65

Scans performed:

  • 📁 Filesystem (vulnerabilities, secrets, misconfigurations)
  • 🐳 Backend Docker image
  • 🐳 Frontend Docker image
  • 🏗️ IaC misconfiguration detection

❌ CRITICAL vulnerabilities must be resolved before merge.

📋 View detailed SARIF reports

Download artifacts from this workflow run for full SARIF reports.
Results are also available in the GitHub Security tab.


Trivy v0.71.0 | aquasecurity/trivy

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.

1 participant