fix(gateway): prevent browser rate-limit self-DoS on missing credentials#38725
fix(gateway): prevent browser rate-limit self-DoS on missing credentials#38725ademczuk wants to merge 2 commits intoopenclaw:mainfrom
Conversation
Greptile SummaryThis PR successfully fixes a self-DoS bug where opening the web UI without credentials would exhaust the browser rate-limit and lock out all connections from that IP. The fix is well-scoped and applied in two complementary layers: the server stops counting absent credentials as rate-limit failures, and the browser client stops auto-reconnecting when it receives an auth error that cannot resolve without user action. Key strengths:
Confidence Score: 5/5
Last reviewed commit: 0e7ce3a |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0e7ce3ab64
ℹ️ 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".
0e7ce3a to
a2c70fe
Compare
🔒 Aisle Security AnalysisWe found 1 potential security issue(s) in this PR:
1. 🟡 Rate-limit bypass for missing gateway credentials enables unthrottled auth attempts (DoS)
Description
Why this is a practical bypass:
Vulnerable code (missing-credential early return without recording a failure): if (!connectAuth?.token) {
// ...
return { ok: false, reason: "token_missing" };
}A similar branch exists for Relevant limiter behavior:
RecommendationTreat missing credentials as rate-limit relevant events or introduce a separate limiter for "missing credential" floods. Option A (simplest): record failures for missing credentials too: if (!connectAuth?.token) {
limiter?.recordFailure(ip, rateLimitScope);
return { ok: false, reason: "token_missing" };
}
if (!password) {
limiter?.recordFailure(ip, rateLimitScope);
return { ok: false, reason: "password_missing" };
}Option B (better UX): use a separate scope and/or higher threshold for missing credentials (to avoid locking out legitimate misconfigured clients while still preventing floods): const missingScope = `${rateLimitScope}:missing`;
if (!connectAuth?.token) {
limiter?.recordFailure(ip, missingScope);
return { ok: false, reason: "token_missing" };
}Also consider adding a lightweight per-IP connection attempt limiter at the WebSocket/HTTP entrypoint to protect CPU/logs regardless of auth result. Analyzed PR: #38725 at commit Last updated on: 2026-03-07T22:48:18Z |
|
@Takhoffman - this could use a review when you've got a moment. Context: Fixes a browser rate-limit self-DoS where missing auth credentials trigger The "Changes at a glance" table in the description has the exact lines to review. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a2c70fe6e4
ℹ️ 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".
6aaf200 to
b6bb58d
Compare
b6bb58d to
1d84b43
Compare
|
Rebased onto latest main (70 commits forward). No content changes - same single commit, just synced with upstream. The |
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).
1d84b43 to
533ff3e
Compare
|
Valid concern, but the trade-off is intentional. Missing credentials carry zero brute-force risk - there's nothing to guess. The real-world problem this PR fixes is more severe: a single misconfigured browser triggers The existing Your separate-scope suggestion is reasonable for defence in depth - worth exploring as a follow-up. The connection-level rate limiting in |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 533ff3e70b
ℹ️ 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".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b15e4ca736
ℹ️ 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".
|
Landed on Source commit from this PR: 533ff3e What I kept:
Gate run before landing:
Thanks @ademczuk. |
|
Landed on
Thanks @ademczuk. |
|
Thanks for landing this one. Glad the rate-limit exemption and reconnect gating made the cut. |
Source: openclaw#38725 / 533ff3e by @ademczuk. Thanks @ademczuk. Co-authored-by: ademczuk <andrew.demczuk@gmail.com>
Source: openclaw#38725 / 533ff3e by @ademczuk. Thanks @ademczuk. Co-authored-by: ademczuk <andrew.demczuk@gmail.com>
Source: openclaw#38725 / 533ff3e by @ademczuk. Thanks @ademczuk. Co-authored-by: ademczuk <andrew.demczuk@gmail.com>
Source: openclaw#38725 / 533ff3e by @ademczuk. Thanks @ademczuk. Co-authored-by: ademczuk <andrew.demczuk@gmail.com>
Source: openclaw#38725 / 533ff3e by @ademczuk. Thanks @ademczuk. Co-authored-by: ademczuk <andrew.demczuk@gmail.com>
Source: openclaw#38725 / 533ff3e by @ademczuk. Thanks @ademczuk. Co-authored-by: ademczuk <andrew.demczuk@gmail.com>
Source: openclaw#38725 / 533ff3e by @ademczuk. Thanks @ademczuk. Co-authored-by: ademczuk <andrew.demczuk@gmail.com>
Source: openclaw#38725 / 533ff3e by @ademczuk. Thanks @ademczuk. Co-authored-by: ademczuk <andrew.demczuk@gmail.com> (cherry picked from commit 3a74dc0)
Source: openclaw#38725 / 533ff3e by @ademczuk. Thanks @ademczuk. Co-authored-by: ademczuk <andrew.demczuk@gmail.com> (cherry picked from commit 3a74dc0)
Source: openclaw#38725 / 533ff3e by @ademczuk. Thanks @ademczuk. Co-authored-by: ademczuk <andrew.demczuk@gmail.com> (cherry picked from commit 3a74dc0)
Source: openclaw#38725 / 533ff3e by @ademczuk. Thanks @ademczuk. Co-authored-by: ademczuk <andrew.demczuk@gmail.com> (cherry picked from commit 3a74dc0)
Source: openclaw#38725 / 533ff3e by @ademczuk. Thanks @ademczuk. Co-authored-by: ademczuk <andrew.demczuk@gmail.com>
Source: openclaw#38725 / 533ff3e by @ademczuk. Thanks @ademczuk. Co-authored-by: ademczuk <andrew.demczuk@gmail.com>
Source: openclaw#38725 / 533ff3e by @ademczuk. Thanks @ademczuk. Co-authored-by: ademczuk <andrew.demczuk@gmail.com>
Summary
?token=triggers a self-DoS: missing credentials count as rate-limit failures, and the browser auto-reconnects, exhausting the limit in ~40 seconds, leading to a 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_PASSWORD_MISMATCH,AUTH_RATE_LIMITED).browserRateLimiterconfig, rate limiter internals, device-token fallback flow (AUTH_TOKEN_MISMATCHdeliberately NOT in the non-recoverable list, since the stale device-token to shared-token retry flow needs reconnect).Continuation of #36138 (closed due to unrelated changes drifting into the branch). This PR contains only the gateway auth fix, the same 2 source files that received a 4/5 from Greptile with "No issues found."
Changes at a glance
src/gateway/auth.ts:L45-L52recordFailure()fortoken_missing/password_missingui/src/ui/gateway.ts:L1-L30isNonRecoverableAuthError()gate beforescheduleReconnect()src/gateway/auth.test.tssrc/gateway/reconnect-gating.test.tsChange Type
Linked Issue
Fixes #28997
Verification
Risks and Mitigations