fix(gateway): prevent browser rate-limit death spiral on missing credentials#36138
fix(gateway): prevent browser rate-limit death spiral on missing credentials#36138ademczuk wants to merge 5 commits intoopenclaw:mainfrom
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4e818b1537
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Greptile SummaryThis PR fixes a self-DoS cascade where opening the browser UI without credentials could trigger the rate-limiter and lock out all connections from that IP for 5 minutes. The fix has two parts: on the server, Key design decisions are sound:
No issues found in the changed files. Confidence Score: 4/5
Last reviewed commit: 19f68ad |
Updates (d123c9b)CI fix: The Fixed in a separate commit (
Bot feedback (f91a757): Added All checks pass locally: |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d123c9b173
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
9796adb to
c5667de
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c5667def48
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
c5667de to
19f68ad
Compare
|
@Takhoffman — This is a focused gateway auth fix (2 files, ~30 lines). Summary: The browser WebSocket client can trigger a rate-limit death spiral when connecting without a pre-configured token:
Fix:
Note: Rebased cleanly onto current main (dropped the mattermost import commit since your #36480 already landed). |
|
@joshavant — would you mind reviewing this? Small 2-file fix for a browser rate-limiter self-DoS. CI all green. The bug: a single browser tab without a pre-configured token triggers an unrecoverable cascade — Fix 1 ( |
19f68ad to
417deb5
Compare
Test Coverage Added (417deb5)Added unit tests verifying both fixes: Fix 1 —
Fix 2 —
All 44 gateway tests pass (36 auth + 8 reconnect gating). |
|
@vincentkoc — small gateway auth fix (2 files, +139/-4, size:S). CI all green, all bot comments addressed. The bug: A single browser tab without a pre-configured token triggers a rate-limit death spiral — The fix: (1) Stop counting missing credentials as failures — only actual mismatches burn slots. (2) Stop auto-reconnecting on non-recoverable auth errors. Would appreciate a quick look when you have a moment. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 66f4360692
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…entials Don't count missing credentials (no token/password provided) as auth failures in the rate limiter — only actual mismatches should burn slots. Previously, opening the web UI without a token triggered recordFailure() on every connect attempt, exhausting the rate limit in ~40 seconds and locking the user out for 5 minutes. Also stop the browser client from auto-reconnecting on non-recoverable auth errors (missing token, missing password, rate-limited), since these won't resolve without user action and the reconnect loop accelerates the lockout cascade. Fixes openclaw#28997 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- auth.test.ts: verify token_missing and password_missing do NOT call recordFailure (misconfigured client ≠ brute-force) - auth.test.ts: verify token_mismatch and password_mismatch still DO call recordFailure (actual brute-force attempts) - reconnect-gating.test.ts: verify isNonRecoverableAuthError blocks reconnect for missing/mismatch/rate-limited but allows reconnect for token_mismatch (device-token fallback flow) and unknown codes Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
66f4360 to
56eda54
Compare
|
Unrelated changes in this PR |
Stop counting missing credentials (token_missing, password_missing) as rate-limit failures — a misconfigured browser is not a brute-force attack. Stop auto-reconnecting on non-recoverable auth errors (missing token, missing password, wrong password, rate-limited). Preserve device-token fallback by allowing reconnect on token mismatch. Includes unit tests for both fixes (12 new tests, all passing). Continuation of openclaw#36138 (closed due to unrelated changes drifting in).
Summary
?token=triggers a self-DoS: missing credentials count as rate-limit failures, and the browser auto-reconnects, exhausting the limit in ~40 seconds → 5-minute lockout for ALL browser connections from that IP.auth.ts— stop callingrecordFailure()fortoken_missing/password_missing; only actual mismatches burn rate-limit slots. (2)gateway.ts— stop auto-reconnecting on non-recoverable auth errors (AUTH_TOKEN_MISSING,AUTH_PASSWORD_MISSING,AUTH_RATE_LIMITED).browserRateLimiterconfig (includingexemptLoopback: false),198.18.0.1synthetic IP mapping, rate limiter internals, device-token fallback flow (AUTH_TOKEN_MISMATCHdeliberately NOT in the non-recoverable list).Change Type (select all)
Scope (select all touched areas)
Linked Issue/PR
User-visible / Behavior Changes
Security Impact (required)
NoYes— narrowed what counts as a rate-limit failure. Missing credentials are no longer penalized; only wrong credentials (mismatch) burn slots.NoNoNorecordFailure()for missing tokens means a client that repeatedly connects without any token won't be rate-limited. This is acceptable because: (a) missing-token connections fail immediately with no server-side resource consumption, (b) actual brute-force probes use wrong tokens (mismatch), which are still rate-limited, (c) the gateway should not be exposed without auth in production.Repro + Verification
Environment
gateway.auth.rateLimit.maxAttempts: 10(default)Steps
?token=parameterExpected
Browser shows auth error, does NOT auto-reconnect, no rate-limit penalty.
Actual
Before: 10 auto-reconnects in ~40s → rate-limit lockout for 5 minutes → all browser connections rejected.
After: Single connection attempt → auth error displayed → no reconnect → no rate-limit impact.
Evidence
50 tests pass:
auth.test.ts(31),auth-rate-limit.test.ts(18), reconnect gating test (1).Human Verification (required)
AUTH_TOKEN_MISMATCHdeliberately excluded from non-recoverable list to preserve device-token → shared-token fallback flow (stale device token → mismatch →sendConnect()clears → reconnect with shared token succeeds).Compatibility / Migration
YesNoNoFailure Recovery (if this breaks)
git revert <sha>on the merge commit, or restore these two files:src/gateway/auth.ts— re-addrecordFailure()calls fortoken_missing/password_missingui/src/ui/gateway.ts— removeisNonRecoverableAuthError()check beforescheduleReconnect()token_mismatchstill triggersrecordFailure()).Risks and Mitigations
Risk: No-token connections are no longer rate-limited, theoretically allowing connection flooding without penalty.
browserRateLimiterwithexemptLoopback: falsestill protects against remote attackers.Risk: Non-recoverable error list may need updating if new auth error codes are added upstream.
AUTH_TOKEN_MISSING,AUTH_PASSWORD_MISSING,AUTH_RATE_LIMITED) is conservative — only errors that provably cannot resolve without user action. New error codes default to allowing reconnect (safe default).