fix(gateway): reject RPCs from invalidated device-token clients durin…#70707
fix(gateway): reject RPCs from invalidated device-token clients durin…#70707davidangularme wants to merge 3 commits intoopenclaw:mainfrom
Conversation
Greptile SummaryThis PR closes a race condition in the gateway where RPCs pipelined in a WebSocket buffer could be processed after a token rotation/revoke because the socket close was deferred via Confidence Score: 5/5Safe to merge — the fix is targeted, well-tested, and idempotent. No blocking issues found. All findings are P2 or lower. The core security fix is correct: No files require special attention. Reviews (1): Last reviewed commit: "fix(gateway): reject RPCs from invalidat..." | Re-trigger Greptile |
|
Codex review: needs changes before merge. Summary Reproducibility: yes. Current main gives a high-confidence source-level reproduction: the affected handlers respond before queueMicrotask disconnect, and the dispatcher lacks a device-token invalidation recheck before handler logic. Next step before merge Security Review findings
Review detailsBest possible solution: Land this PR, or an equivalent narrow mainline patch, after adding the required changelog entry and confirming exact-head gateway checks. Do we have a high-confidence way to reproduce the issue? Yes. Current main gives a high-confidence source-level reproduction: the affected handlers respond before queueMicrotask disconnect, and the dispatcher lacks a device-token invalidation recheck before handler logic. Is this the best way to solve the issue? Yes. The in-memory invalidated flag plus pre-dispatch close is the narrowest maintainable fix I found for preserving response flushing while closing the queued-RPC window; the patch needs only merge-prep cleanup. Full review comments:
Overall correctness: patch is correct Acceptance criteria:
What I checked:
Likely related people:
Remaining risk / open question:
Codex review notes: model gpt-5.5, reasoning high; reviewed against 9bedcff904dd. |
84c0364 to
ba47c72
Compare
…g rotation/revoke race device.token.rotate, device.token.revoke and device.pair.remove all respond 200 OK to the admin, then schedule disconnectClientsForDevice via queueMicrotask so the response can flush before the socket close. That microtask window plus the absence of a per-RPC re-check for device-token auth (unlike shared-auth, which gets checked at message-handler.ts:1444-1458) created a race: an attacker with RPCs already pipelined in the WS socket buffer could land a few more authenticated operations with the rotated/revoked token before the socket actually closed. Fix: add a cheap in-memory 'invalidated' flag on GatewayWsClient and mark it synchronously *before* responding in the three handlers. Add a mirror check at the start of the per-RPC dispatch that force-closes the client if the flag is set, regardless of whether socket.close() has taken effect yet. Disconnect still happens via queueMicrotask so the admin's rotate/revoke response flushes normally. Introduces context.invalidateClientsForDevice(deviceId, opts) as a sync companion to the existing disconnectClientsForDevice. Also defense-in-depth: disconnectClientsForDevice now sets the flag too, so any other caller of the hard-disconnect path gets the per-RPC gate for free.
…tests check-test-types failed on the PR because direct 'as ReturnType<typeof vi.fn>' casts from RespondFn (or the optional context methods) don't structurally overlap with the Mock type — Mock has mockImplementation/mockReturnValue that RespondFn lacks, so strict tsgo rejects the conversion. vi.mocked() is the intended helper for reinterpreting an already-mocked function, and drops through to the Mock surface cleanly.
After rebasing onto upstream main, two test surfaces drifted:
1. GatewayRequestContextParams gained two required fields upstream
(getRuntimeConfig, broadcastVoiceWakeRoutingChanged). The
makeContextParams test helper was missing them, so every consumer
tripped tsgo with a missing-field error. Add both as vi.fn()
stubs.
2. revokeDeviceToken's return shape changed upstream from a bare
entry record to a discriminated union {ok: true, entry: ...} | {ok:
false, reason}. The new device.token.revoke synchronous-invalidate
test still mocked the old shape, so the production handler took the
!revoked.ok branch and never reached the invalidateClientsForDevice
call the test asserted. Update the mock to the new union shape.
Also fix three new Set([...] as never) sites in server-request-
context.test.ts that produced Set<unknown> rather than Set<never>.
Move the cast outside the Set constructor so the literal stays
inferred while the wrapper is type-erased to never, which is
assignable to the Partial<GatewayRequestContextParams> clients field.
c006b1c to
779f657
Compare
|
Hi @steipete, @vincentkoc, I've rebased the branch to align with the latest upstream changes. While the Opus 4.6 parity gate is failing on scenario 10, all 73 other checks—including the new unit tests for synchronous invalidation—are passing successfully. This specific parity failure seems to be a pre-existing issue in the QA lab environment rather than a regression from the security fix. I've also addressed the blank-template triage flags in the PR description. Ready for your review. |
…audit Gap 1 (Critical CWE-208): Replace !== with safeEqualSecret() for TLS fingerprint comparison in client.ts, eliminating timing side-channel attacks on WebSocket and HTTP TLS pinning. Refs: openclaw/openclaw#49083 Gap 2 (High revocation race): Add sync invalidated flag on GatewayClient, set before respond() in device.token.rotate/revoke and device.pair.remove handlers, with per-RPC dispatch guard in message-handler to reject pipelined RPCs from revoked credentials. Refs: openclaw/openclaw#70707 Gap 4 (High unbounded sessions): Add authenticated-connection-budget.ts per-device connection cap (default 8) with env override. Refs: openclaw/openclaw#59842 Gap 6 (High HTTP flood): Add request-rate-limit.ts sliding-window per-IP HTTP request rate limiter (default 120/min) for REST endpoints. Refs: openclaw/openclaw#44884 Gap 7 (High TLS enforcement): Add startup-security-checks.ts for network-exposure safety checks at startup. Refs: openclaw/openclaw#44884 Gap 8 (Medium auto HSTS): Auto-inject HSTS when TLS is active. Refs: openclaw/openclaw#44884 Gap 9 (Medium bind safety): Bind-all-interfaces detection via startup checks. Refs: openclaw/openclaw#44884 Gaps 3, 5, 10 already fixed in fork — no changes needed.
…audit Gap 1 (Critical CWE-208): Replace !== with safeEqualSecret() for TLS fingerprint comparison in client.ts, eliminating timing side-channel attacks on WebSocket and HTTP TLS pinning. Refs: openclaw/openclaw#49083 Gap 2 (High revocation race): Add sync invalidated flag on GatewayClient, set before respond() in device.token.rotate/revoke and device.pair.remove handlers, with per-RPC dispatch guard in message-handler to reject pipelined RPCs from revoked credentials. Refs: openclaw/openclaw#70707 Gap 4 (High unbounded sessions): Add authenticated-connection-budget.ts per-device connection cap (default 8) with env override. Refs: openclaw/openclaw#59842 Gap 6 (High HTTP flood): Add request-rate-limit.ts sliding-window per-IP HTTP request rate limiter (default 120/min) for REST endpoints. Refs: openclaw/openclaw#44884 Gap 7 (High TLS enforcement): Add startup-security-checks.ts for network-exposure safety checks at startup. Refs: openclaw/openclaw#44884 Gap 8 (Medium auto HSTS): Auto-inject HSTS when TLS is active. Refs: openclaw/openclaw#44884 Gap 9 (Medium bind safety): Bind-all-interfaces detection via startup checks. Refs: openclaw/openclaw#44884 Gaps 3, 5, 10 already fixed in fork — no changes needed.
…audit Gap 1 (Critical CWE-208): Replace !== with safeEqualSecret() for TLS fingerprint comparison in client.ts, eliminating timing side-channel attacks on WebSocket and HTTP TLS pinning. Refs: openclaw/openclaw#49083 Gap 2 (High revocation race): Add sync invalidated flag on GatewayClient, set before respond() in device.token.rotate/revoke and device.pair.remove handlers, with per-RPC dispatch guard in message-handler to reject pipelined RPCs from revoked credentials. Refs: openclaw/openclaw#70707 Gap 4 (High unbounded sessions): Add authenticated-connection-budget.ts per-device connection cap (default 8) with env override. Refs: openclaw/openclaw#59842 Gap 6 (High HTTP flood): Add request-rate-limit.ts sliding-window per-IP HTTP request rate limiter (default 120/min) for REST endpoints. Refs: openclaw/openclaw#44884 Gap 7 (High TLS enforcement): Add startup-security-checks.ts for network-exposure safety checks at startup. Refs: openclaw/openclaw#44884 Gap 8 (Medium auto HSTS): Auto-inject HSTS when TLS is active. Refs: openclaw/openclaw#44884 Gap 9 (Medium bind safety): Bind-all-interfaces detection via startup checks. Refs: openclaw/openclaw#44884 Gaps 3, 5, 10 already fixed in fork — no changes needed.
…audit Gap 1 (Critical CWE-208): Replace !== with safeEqualSecret() for TLS fingerprint comparison in client.ts, eliminating timing side-channel attacks on WebSocket and HTTP TLS pinning. Refs: openclaw/openclaw#49083 Gap 2 (High revocation race): Add sync invalidated flag on GatewayClient, set before respond() in device.token.rotate/revoke and device.pair.remove handlers, with per-RPC dispatch guard in message-handler to reject pipelined RPCs from revoked credentials. Refs: openclaw/openclaw#70707 Gap 4 (High unbounded sessions): Add authenticated-connection-budget.ts per-device connection cap (default 8) with env override. Refs: openclaw/openclaw#59842 Gap 6 (High HTTP flood): Add request-rate-limit.ts sliding-window per-IP HTTP request rate limiter (default 120/min) for REST endpoints. Refs: openclaw/openclaw#44884 Gap 7 (High TLS enforcement): Add startup-security-checks.ts for network-exposure safety checks at startup. Refs: openclaw/openclaw#44884 Gap 8 (Medium auto HSTS): Auto-inject HSTS when TLS is active. Refs: openclaw/openclaw#44884 Gap 9 (Medium bind safety): Bind-all-interfaces detection via startup checks. Refs: openclaw/openclaw#44884 Gaps 3, 5, 10 already fixed in fork — no changes needed.
…audit Gap 1 (Critical CWE-208): Replace !== with safeEqualSecret() for TLS fingerprint comparison in client.ts, eliminating timing side-channel attacks on WebSocket and HTTP TLS pinning. Refs: openclaw/openclaw#49083 Gap 2 (High revocation race): Add sync invalidated flag on GatewayClient, set before respond() in device.token.rotate/revoke and device.pair.remove handlers, with per-RPC dispatch guard in message-handler to reject pipelined RPCs from revoked credentials. Refs: openclaw/openclaw#70707 Gap 4 (High unbounded sessions): Add authenticated-connection-budget.ts per-device connection cap (default 8) with env override. Refs: openclaw/openclaw#59842 Gap 6 (High HTTP flood): Add request-rate-limit.ts sliding-window per-IP HTTP request rate limiter (default 120/min) for REST endpoints. Refs: openclaw/openclaw#44884 Gap 7 (High TLS enforcement): Add startup-security-checks.ts for network-exposure safety checks at startup. Refs: openclaw/openclaw#44884 Gap 8 (Medium auto HSTS): Auto-inject HSTS when TLS is active. Refs: openclaw/openclaw#44884 Gap 9 (Medium bind safety): Bind-all-interfaces detection via startup checks. Refs: openclaw/openclaw#44884 Gaps 3, 5, 10 already fixed in fork — no changes needed.
…audit Gap 1 (Critical CWE-208): Replace !== with safeEqualSecret() for TLS fingerprint comparison in client.ts, eliminating timing side-channel attacks on WebSocket and HTTP TLS pinning. Refs: openclaw/openclaw#49083 Gap 2 (High revocation race): Add sync invalidated flag on GatewayClient, set before respond() in device.token.rotate/revoke and device.pair.remove handlers, with per-RPC dispatch guard in message-handler to reject pipelined RPCs from revoked credentials. Refs: openclaw/openclaw#70707 Gap 4 (High unbounded sessions): Add authenticated-connection-budget.ts per-device connection cap (default 8) with env override. Refs: openclaw/openclaw#59842 Gap 6 (High HTTP flood): Add request-rate-limit.ts sliding-window per-IP HTTP request rate limiter (default 120/min) for REST endpoints. Refs: openclaw/openclaw#44884 Gap 7 (High TLS enforcement): Add startup-security-checks.ts for network-exposure safety checks at startup. Refs: openclaw/openclaw#44884 Gap 8 (Medium auto HSTS): Auto-inject HSTS when TLS is active. Refs: openclaw/openclaw#44884 Gap 9 (Medium bind safety): Bind-all-interfaces detection via startup checks. Refs: openclaw/openclaw#44884 Gaps 3, 5, 10 already fixed in fork — no changes needed.
…audit Gap 1 (Critical CWE-208): Replace !== with safeEqualSecret() for TLS fingerprint comparison in client.ts, eliminating timing side-channel attacks on WebSocket and HTTP TLS pinning. Refs: openclaw/openclaw#49083 Gap 2 (High revocation race): Add sync invalidated flag on GatewayClient, set before respond() in device.token.rotate/revoke and device.pair.remove handlers, with per-RPC dispatch guard in message-handler to reject pipelined RPCs from revoked credentials. Refs: openclaw/openclaw#70707 Gap 4 (High unbounded sessions): Add authenticated-connection-budget.ts per-device connection cap (default 8) with env override. Refs: openclaw/openclaw#59842 Gap 6 (High HTTP flood): Add request-rate-limit.ts sliding-window per-IP HTTP request rate limiter (default 120/min) for REST endpoints. Refs: openclaw/openclaw#44884 Gap 7 (High TLS enforcement): Add startup-security-checks.ts for network-exposure safety checks at startup. Refs: openclaw/openclaw#44884 Gap 8 (Medium auto HSTS): Auto-inject HSTS when TLS is active. Refs: openclaw/openclaw#44884 Gap 9 (Medium bind safety): Bind-all-interfaces detection via startup checks. Refs: openclaw/openclaw#44884 Gaps 3, 5, 10 already fixed in fork — no changes needed.
…audit Gap 1 (Critical CWE-208): Replace !== with safeEqualSecret() for TLS fingerprint comparison in client.ts, eliminating timing side-channel attacks on WebSocket and HTTP TLS pinning. Refs: openclaw/openclaw#49083 Gap 2 (High revocation race): Add sync invalidated flag on GatewayClient, set before respond() in device.token.rotate/revoke and device.pair.remove handlers, with per-RPC dispatch guard in message-handler to reject pipelined RPCs from revoked credentials. Refs: openclaw/openclaw#70707 Gap 4 (High unbounded sessions): Add authenticated-connection-budget.ts per-device connection cap (default 8) with env override. Refs: openclaw/openclaw#59842 Gap 6 (High HTTP flood): Add request-rate-limit.ts sliding-window per-IP HTTP request rate limiter (default 120/min) for REST endpoints. Refs: openclaw/openclaw#44884 Gap 7 (High TLS enforcement): Add startup-security-checks.ts for network-exposure safety checks at startup. Refs: openclaw/openclaw#44884 Gap 8 (Medium auto HSTS): Auto-inject HSTS when TLS is active. Refs: openclaw/openclaw#44884 Gap 9 (Medium bind safety): Bind-all-interfaces detection via startup checks. Refs: openclaw/openclaw#44884 Gaps 3, 5, 10 already fixed in fork — no changes needed.
…audit Gap 1 (Critical CWE-208): Replace !== with safeEqualSecret() for TLS fingerprint comparison in client.ts, eliminating timing side-channel attacks on WebSocket and HTTP TLS pinning. Refs: openclaw/openclaw#49083 Gap 2 (High revocation race): Add sync invalidated flag on GatewayClient, set before respond() in device.token.rotate/revoke and device.pair.remove handlers, with per-RPC dispatch guard in message-handler to reject pipelined RPCs from revoked credentials. Refs: openclaw/openclaw#70707 Gap 4 (High unbounded sessions): Add authenticated-connection-budget.ts per-device connection cap (default 8) with env override. Refs: openclaw/openclaw#59842 Gap 6 (High HTTP flood): Add request-rate-limit.ts sliding-window per-IP HTTP request rate limiter (default 120/min) for REST endpoints. Refs: openclaw/openclaw#44884 Gap 7 (High TLS enforcement): Add startup-security-checks.ts for network-exposure safety checks at startup. Refs: openclaw/openclaw#44884 Gap 8 (Medium auto HSTS): Auto-inject HSTS when TLS is active. Refs: openclaw/openclaw#44884 Gap 9 (Medium bind safety): Bind-all-interfaces detection via startup checks. Refs: openclaw/openclaw#44884 Gaps 3, 5, 10 already fixed in fork — no changes needed.
…audit Gap 1 (Critical CWE-208): Replace !== with safeEqualSecret() for TLS fingerprint comparison in client.ts, eliminating timing side-channel attacks on WebSocket and HTTP TLS pinning. Refs: openclaw/openclaw#49083 Gap 2 (High revocation race): Add sync invalidated flag on GatewayClient, set before respond() in device.token.rotate/revoke and device.pair.remove handlers, with per-RPC dispatch guard in message-handler to reject pipelined RPCs from revoked credentials. Refs: openclaw/openclaw#70707 Gap 4 (High unbounded sessions): Add authenticated-connection-budget.ts per-device connection cap (default 8) with env override. Refs: openclaw/openclaw#59842 Gap 6 (High HTTP flood): Add request-rate-limit.ts sliding-window per-IP HTTP request rate limiter (default 120/min) for REST endpoints. Refs: openclaw/openclaw#44884 Gap 7 (High TLS enforcement): Add startup-security-checks.ts for network-exposure safety checks at startup. Refs: openclaw/openclaw#44884 Gap 8 (Medium auto HSTS): Auto-inject HSTS when TLS is active. Refs: openclaw/openclaw#44884 Gap 9 (Medium bind safety): Bind-all-interfaces detection via startup checks. Refs: openclaw/openclaw#44884 Gaps 3, 5, 10 already fixed in fork — no changes needed.
…audit Gap 1 (Critical CWE-208): Replace !== with safeEqualSecret() for TLS fingerprint comparison in client.ts, eliminating timing side-channel attacks on WebSocket and HTTP TLS pinning. Refs: openclaw/openclaw#49083 Gap 2 (High revocation race): Add sync invalidated flag on GatewayClient, set before respond() in device.token.rotate/revoke and device.pair.remove handlers, with per-RPC dispatch guard in message-handler to reject pipelined RPCs from revoked credentials. Refs: openclaw/openclaw#70707 Gap 4 (High unbounded sessions): Add authenticated-connection-budget.ts per-device connection cap (default 8) with env override. Refs: openclaw/openclaw#59842 Gap 6 (High HTTP flood): Add request-rate-limit.ts sliding-window per-IP HTTP request rate limiter (default 120/min) for REST endpoints. Refs: openclaw/openclaw#44884 Gap 7 (High TLS enforcement): Add startup-security-checks.ts for network-exposure safety checks at startup. Refs: openclaw/openclaw#44884 Gap 8 (Medium auto HSTS): Auto-inject HSTS when TLS is active. Refs: openclaw/openclaw#44884 Gap 9 (Medium bind safety): Bind-all-interfaces detection via startup checks. Refs: openclaw/openclaw#44884 Gaps 3, 5, 10 already fixed in fork — no changes needed.
…audit Gap 1 (Critical CWE-208): Replace !== with safeEqualSecret() for TLS fingerprint comparison in client.ts, eliminating timing side-channel attacks on WebSocket and HTTP TLS pinning. Refs: openclaw/openclaw#49083 Gap 2 (High revocation race): Add sync invalidated flag on GatewayClient, set before respond() in device.token.rotate/revoke and device.pair.remove handlers, with per-RPC dispatch guard in message-handler to reject pipelined RPCs from revoked credentials. Refs: openclaw/openclaw#70707 Gap 4 (High unbounded sessions): Add authenticated-connection-budget.ts per-device connection cap (default 8) with env override. Refs: openclaw/openclaw#59842 Gap 6 (High HTTP flood): Add request-rate-limit.ts sliding-window per-IP HTTP request rate limiter (default 120/min) for REST endpoints. Refs: openclaw/openclaw#44884 Gap 7 (High TLS enforcement): Add startup-security-checks.ts for network-exposure safety checks at startup. Refs: openclaw/openclaw#44884 Gap 8 (Medium auto HSTS): Auto-inject HSTS when TLS is active. Refs: openclaw/openclaw#44884 Gap 9 (Medium bind safety): Bind-all-interfaces detection via startup checks. Refs: openclaw/openclaw#44884 Gaps 3, 5, 10 already fixed in fork — no changes needed.
…audit Gap 1 (Critical CWE-208): Replace !== with safeEqualSecret() for TLS fingerprint comparison in client.ts, eliminating timing side-channel attacks on WebSocket and HTTP TLS pinning. Refs: openclaw/openclaw#49083 Gap 2 (High revocation race): Add sync invalidated flag on GatewayClient, set before respond() in device.token.rotate/revoke and device.pair.remove handlers, with per-RPC dispatch guard in message-handler to reject pipelined RPCs from revoked credentials. Refs: openclaw/openclaw#70707 Gap 4 (High unbounded sessions): Add authenticated-connection-budget.ts per-device connection cap (default 8) with env override. Refs: openclaw/openclaw#59842 Gap 6 (High HTTP flood): Add request-rate-limit.ts sliding-window per-IP HTTP request rate limiter (default 120/min) for REST endpoints. Refs: openclaw/openclaw#44884 Gap 7 (High TLS enforcement): Add startup-security-checks.ts for network-exposure safety checks at startup. Refs: openclaw/openclaw#44884 Gap 8 (Medium auto HSTS): Auto-inject HSTS when TLS is active. Refs: openclaw/openclaw#44884 Gap 9 (Medium bind safety): Bind-all-interfaces detection via startup checks. Refs: openclaw/openclaw#44884 Gaps 3, 5, 10 already fixed in fork — no changes needed.
…audit Gap 1 (Critical CWE-208): Replace !== with safeEqualSecret() for TLS fingerprint comparison in client.ts, eliminating timing side-channel attacks on WebSocket and HTTP TLS pinning. Refs: openclaw/openclaw#49083 Gap 2 (High revocation race): Add sync invalidated flag on GatewayClient, set before respond() in device.token.rotate/revoke and device.pair.remove handlers, with per-RPC dispatch guard in message-handler to reject pipelined RPCs from revoked credentials. Refs: openclaw/openclaw#70707 Gap 4 (High unbounded sessions): Add authenticated-connection-budget.ts per-device connection cap (default 8) with env override. Refs: openclaw/openclaw#59842 Gap 6 (High HTTP flood): Add request-rate-limit.ts sliding-window per-IP HTTP request rate limiter (default 120/min) for REST endpoints. Refs: openclaw/openclaw#44884 Gap 7 (High TLS enforcement): Add startup-security-checks.ts for network-exposure safety checks at startup. Refs: openclaw/openclaw#44884 Gap 8 (Medium auto HSTS): Auto-inject HSTS when TLS is active. Refs: openclaw/openclaw#44884 Gap 9 (Medium bind safety): Bind-all-interfaces detection via startup checks. Refs: openclaw/openclaw#44884 Gaps 3, 5, 10 already fixed in fork — no changes needed.
…audit Gap 1 (Critical CWE-208): Replace !== with safeEqualSecret() for TLS fingerprint comparison in client.ts, eliminating timing side-channel attacks on WebSocket and HTTP TLS pinning. Refs: openclaw/openclaw#49083 Gap 2 (High revocation race): Add sync invalidated flag on GatewayClient, set before respond() in device.token.rotate/revoke and device.pair.remove handlers, with per-RPC dispatch guard in message-handler to reject pipelined RPCs from revoked credentials. Refs: openclaw/openclaw#70707 Gap 4 (High unbounded sessions): Add authenticated-connection-budget.ts per-device connection cap (default 8) with env override. Refs: openclaw/openclaw#59842 Gap 6 (High HTTP flood): Add request-rate-limit.ts sliding-window per-IP HTTP request rate limiter (default 120/min) for REST endpoints. Refs: openclaw/openclaw#44884 Gap 7 (High TLS enforcement): Add startup-security-checks.ts for network-exposure safety checks at startup. Refs: openclaw/openclaw#44884 Gap 8 (Medium auto HSTS): Auto-inject HSTS when TLS is active. Refs: openclaw/openclaw#44884 Gap 9 (Medium bind safety): Bind-all-interfaces detection via startup checks. Refs: openclaw/openclaw#44884 Gaps 3, 5, 10 already fixed in fork — no changes needed.
…audit Gap 1 (Critical CWE-208): Replace !== with safeEqualSecret() for TLS fingerprint comparison in client.ts, eliminating timing side-channel attacks on WebSocket and HTTP TLS pinning. Refs: openclaw/openclaw#49083 Gap 2 (High revocation race): Add sync invalidated flag on GatewayClient, set before respond() in device.token.rotate/revoke and device.pair.remove handlers, with per-RPC dispatch guard in message-handler to reject pipelined RPCs from revoked credentials. Refs: openclaw/openclaw#70707 Gap 4 (High unbounded sessions): Add authenticated-connection-budget.ts per-device connection cap (default 8) with env override. Refs: openclaw/openclaw#59842 Gap 6 (High HTTP flood): Add request-rate-limit.ts sliding-window per-IP HTTP request rate limiter (default 120/min) for REST endpoints. Refs: openclaw/openclaw#44884 Gap 7 (High TLS enforcement): Add startup-security-checks.ts for network-exposure safety checks at startup. Refs: openclaw/openclaw#44884 Gap 8 (Medium auto HSTS): Auto-inject HSTS when TLS is active. Refs: openclaw/openclaw#44884 Gap 9 (Medium bind safety): Bind-all-interfaces detection via startup checks. Refs: openclaw/openclaw#44884 Gaps 3, 5, 10 already fixed in fork — no changes needed.
…audit Gap 1 (Critical CWE-208): Replace !== with safeEqualSecret() for TLS fingerprint comparison in client.ts, eliminating timing side-channel attacks on WebSocket and HTTP TLS pinning. Refs: openclaw/openclaw#49083 Gap 2 (High revocation race): Add sync invalidated flag on GatewayClient, set before respond() in device.token.rotate/revoke and device.pair.remove handlers, with per-RPC dispatch guard in message-handler to reject pipelined RPCs from revoked credentials. Refs: openclaw/openclaw#70707 Gap 4 (High unbounded sessions): Add authenticated-connection-budget.ts per-device connection cap (default 8) with env override. Refs: openclaw/openclaw#59842 Gap 6 (High HTTP flood): Add request-rate-limit.ts sliding-window per-IP HTTP request rate limiter (default 120/min) for REST endpoints. Refs: openclaw/openclaw#44884 Gap 7 (High TLS enforcement): Add startup-security-checks.ts for network-exposure safety checks at startup. Refs: openclaw/openclaw#44884 Gap 8 (Medium auto HSTS): Auto-inject HSTS when TLS is active. Refs: openclaw/openclaw#44884 Gap 9 (Medium bind safety): Bind-all-interfaces detection via startup checks. Refs: openclaw/openclaw#44884 Gaps 3, 5, 10 already fixed in fork — no changes needed.
…audit Gap 1 (Critical CWE-208): Replace !== with safeEqualSecret() for TLS fingerprint comparison in client.ts, eliminating timing side-channel attacks on WebSocket and HTTP TLS pinning. Refs: openclaw/openclaw#49083 Gap 2 (High revocation race): Add sync invalidated flag on GatewayClient, set before respond() in device.token.rotate/revoke and device.pair.remove handlers, with per-RPC dispatch guard in message-handler to reject pipelined RPCs from revoked credentials. Refs: openclaw/openclaw#70707 Gap 4 (High unbounded sessions): Add authenticated-connection-budget.ts per-device connection cap (default 8) with env override. Refs: openclaw/openclaw#59842 Gap 6 (High HTTP flood): Add request-rate-limit.ts sliding-window per-IP HTTP request rate limiter (default 120/min) for REST endpoints. Refs: openclaw/openclaw#44884 Gap 7 (High TLS enforcement): Add startup-security-checks.ts for network-exposure safety checks at startup. Refs: openclaw/openclaw#44884 Gap 8 (Medium auto HSTS): Auto-inject HSTS when TLS is active. Refs: openclaw/openclaw#44884 Gap 9 (Medium bind safety): Bind-all-interfaces detection via startup checks. Refs: openclaw/openclaw#44884 Gaps 3, 5, 10 already fixed in fork — no changes needed.
…audit Gap 1 (Critical CWE-208): Replace !== with safeEqualSecret() for TLS fingerprint comparison in client.ts, eliminating timing side-channel attacks on WebSocket and HTTP TLS pinning. Refs: openclaw/openclaw#49083 Gap 2 (High revocation race): Add sync invalidated flag on GatewayClient, set before respond() in device.token.rotate/revoke and device.pair.remove handlers, with per-RPC dispatch guard in message-handler to reject pipelined RPCs from revoked credentials. Refs: openclaw/openclaw#70707 Gap 4 (High unbounded sessions): Add authenticated-connection-budget.ts per-device connection cap (default 8) with env override. Refs: openclaw/openclaw#59842 Gap 6 (High HTTP flood): Add request-rate-limit.ts sliding-window per-IP HTTP request rate limiter (default 120/min) for REST endpoints. Refs: openclaw/openclaw#44884 Gap 7 (High TLS enforcement): Add startup-security-checks.ts for network-exposure safety checks at startup. Refs: openclaw/openclaw#44884 Gap 8 (Medium auto HSTS): Auto-inject HSTS when TLS is active. Refs: openclaw/openclaw#44884 Gap 9 (Medium bind safety): Bind-all-interfaces detection via startup checks. Refs: openclaw/openclaw#44884 Gaps 3, 5, 10 already fixed in fork — no changes needed.
…audit Gap 1 (Critical CWE-208): Replace !== with safeEqualSecret() for TLS fingerprint comparison in client.ts, eliminating timing side-channel attacks on WebSocket and HTTP TLS pinning. Refs: openclaw/openclaw#49083 Gap 2 (High revocation race): Add sync invalidated flag on GatewayClient, set before respond() in device.token.rotate/revoke and device.pair.remove handlers, with per-RPC dispatch guard in message-handler to reject pipelined RPCs from revoked credentials. Refs: openclaw/openclaw#70707 Gap 4 (High unbounded sessions): Add authenticated-connection-budget.ts per-device connection cap (default 8) with env override. Refs: openclaw/openclaw#59842 Gap 6 (High HTTP flood): Add request-rate-limit.ts sliding-window per-IP HTTP request rate limiter (default 120/min) for REST endpoints. Refs: openclaw/openclaw#44884 Gap 7 (High TLS enforcement): Add startup-security-checks.ts for network-exposure safety checks at startup. Refs: openclaw/openclaw#44884 Gap 8 (Medium auto HSTS): Auto-inject HSTS when TLS is active. Refs: openclaw/openclaw#44884 Gap 9 (Medium bind safety): Bind-all-interfaces detection via startup checks. Refs: openclaw/openclaw#44884 Gaps 3, 5, 10 already fixed in fork — no changes needed.
…audit Gap 1 (Critical CWE-208): Replace !== with safeEqualSecret() for TLS fingerprint comparison in client.ts, eliminating timing side-channel attacks on WebSocket and HTTP TLS pinning. Refs: openclaw/openclaw#49083 Gap 2 (High revocation race): Add sync invalidated flag on GatewayClient, set before respond() in device.token.rotate/revoke and device.pair.remove handlers, with per-RPC dispatch guard in message-handler to reject pipelined RPCs from revoked credentials. Refs: openclaw/openclaw#70707 Gap 4 (High unbounded sessions): Add authenticated-connection-budget.ts per-device connection cap (default 8) with env override. Refs: openclaw/openclaw#59842 Gap 6 (High HTTP flood): Add request-rate-limit.ts sliding-window per-IP HTTP request rate limiter (default 120/min) for REST endpoints. Refs: openclaw/openclaw#44884 Gap 7 (High TLS enforcement): Add startup-security-checks.ts for network-exposure safety checks at startup. Refs: openclaw/openclaw#44884 Gap 8 (Medium auto HSTS): Auto-inject HSTS when TLS is active. Refs: openclaw/openclaw#44884 Gap 9 (Medium bind safety): Bind-all-interfaces detection via startup checks. Refs: openclaw/openclaw#44884 Gaps 3, 5, 10 already fixed in fork — no changes needed.
…audit Gap 1 (Critical CWE-208): Replace !== with safeEqualSecret() for TLS fingerprint comparison in client.ts, eliminating timing side-channel attacks on WebSocket and HTTP TLS pinning. Refs: openclaw/openclaw#49083 Gap 2 (High revocation race): Add sync invalidated flag on GatewayClient, set before respond() in device.token.rotate/revoke and device.pair.remove handlers, with per-RPC dispatch guard in message-handler to reject pipelined RPCs from revoked credentials. Refs: openclaw/openclaw#70707 Gap 4 (High unbounded sessions): Add authenticated-connection-budget.ts per-device connection cap (default 8) with env override. Refs: openclaw/openclaw#59842 Gap 6 (High HTTP flood): Add request-rate-limit.ts sliding-window per-IP HTTP request rate limiter (default 120/min) for REST endpoints. Refs: openclaw/openclaw#44884 Gap 7 (High TLS enforcement): Add startup-security-checks.ts for network-exposure safety checks at startup. Refs: openclaw/openclaw#44884 Gap 8 (Medium auto HSTS): Auto-inject HSTS when TLS is active. Refs: openclaw/openclaw#44884 Gap 9 (Medium bind safety): Bind-all-interfaces detection via startup checks. Refs: openclaw/openclaw#44884 Gaps 3, 5, 10 already fixed in fork — no changes needed.
…audit Gap 1 (Critical CWE-208): Replace !== with safeEqualSecret() for TLS fingerprint comparison in client.ts, eliminating timing side-channel attacks on WebSocket and HTTP TLS pinning. Refs: openclaw/openclaw#49083 Gap 2 (High revocation race): Add sync invalidated flag on GatewayClient, set before respond() in device.token.rotate/revoke and device.pair.remove handlers, with per-RPC dispatch guard in message-handler to reject pipelined RPCs from revoked credentials. Refs: openclaw/openclaw#70707 Gap 4 (High unbounded sessions): Add authenticated-connection-budget.ts per-device connection cap (default 8) with env override. Refs: openclaw/openclaw#59842 Gap 6 (High HTTP flood): Add request-rate-limit.ts sliding-window per-IP HTTP request rate limiter (default 120/min) for REST endpoints. Refs: openclaw/openclaw#44884 Gap 7 (High TLS enforcement): Add startup-security-checks.ts for network-exposure safety checks at startup. Refs: openclaw/openclaw#44884 Gap 8 (Medium auto HSTS): Auto-inject HSTS when TLS is active. Refs: openclaw/openclaw#44884 Gap 9 (Medium bind safety): Bind-all-interfaces detection via startup checks. Refs: openclaw/openclaw#44884 Gaps 3, 5, 10 already fixed in fork — no changes needed.
…audit Gap 1 (Critical CWE-208): Replace !== with safeEqualSecret() for TLS fingerprint comparison in client.ts, eliminating timing side-channel attacks on WebSocket and HTTP TLS pinning. Refs: openclaw/openclaw#49083 Gap 2 (High revocation race): Add sync invalidated flag on GatewayClient, set before respond() in device.token.rotate/revoke and device.pair.remove handlers, with per-RPC dispatch guard in message-handler to reject pipelined RPCs from revoked credentials. Refs: openclaw/openclaw#70707 Gap 4 (High unbounded sessions): Add authenticated-connection-budget.ts per-device connection cap (default 8) with env override. Refs: openclaw/openclaw#59842 Gap 6 (High HTTP flood): Add request-rate-limit.ts sliding-window per-IP HTTP request rate limiter (default 120/min) for REST endpoints. Refs: openclaw/openclaw#44884 Gap 7 (High TLS enforcement): Add startup-security-checks.ts for network-exposure safety checks at startup. Refs: openclaw/openclaw#44884 Gap 8 (Medium auto HSTS): Auto-inject HSTS when TLS is active. Refs: openclaw/openclaw#44884 Gap 9 (Medium bind safety): Bind-all-interfaces detection via startup checks. Refs: openclaw/openclaw#44884 Gaps 3, 5, 10 already fixed in fork — no changes needed.
…audit Gap 1 (Critical CWE-208): Replace !== with safeEqualSecret() for TLS fingerprint comparison in client.ts, eliminating timing side-channel attacks on WebSocket and HTTP TLS pinning. Refs: openclaw/openclaw#49083 Gap 2 (High revocation race): Add sync invalidated flag on GatewayClient, set before respond() in device.token.rotate/revoke and device.pair.remove handlers, with per-RPC dispatch guard in message-handler to reject pipelined RPCs from revoked credentials. Refs: openclaw/openclaw#70707 Gap 4 (High unbounded sessions): Add authenticated-connection-budget.ts per-device connection cap (default 8) with env override. Refs: openclaw/openclaw#59842 Gap 6 (High HTTP flood): Add request-rate-limit.ts sliding-window per-IP HTTP request rate limiter (default 120/min) for REST endpoints. Refs: openclaw/openclaw#44884 Gap 7 (High TLS enforcement): Add startup-security-checks.ts for network-exposure safety checks at startup. Refs: openclaw/openclaw#44884 Gap 8 (Medium auto HSTS): Auto-inject HSTS when TLS is active. Refs: openclaw/openclaw#44884 Gap 9 (Medium bind safety): Bind-all-interfaces detection via startup checks. Refs: openclaw/openclaw#44884 Gaps 3, 5, 10 already fixed in fork — no changes needed.
…audit Gap 1 (Critical CWE-208): Replace !== with safeEqualSecret() for TLS fingerprint comparison in client.ts, eliminating timing side-channel attacks on WebSocket and HTTP TLS pinning. Refs: openclaw/openclaw#49083 Gap 2 (High revocation race): Add sync invalidated flag on GatewayClient, set before respond() in device.token.rotate/revoke and device.pair.remove handlers, with per-RPC dispatch guard in message-handler to reject pipelined RPCs from revoked credentials. Refs: openclaw/openclaw#70707 Gap 4 (High unbounded sessions): Add authenticated-connection-budget.ts per-device connection cap (default 8) with env override. Refs: openclaw/openclaw#59842 Gap 6 (High HTTP flood): Add request-rate-limit.ts sliding-window per-IP HTTP request rate limiter (default 120/min) for REST endpoints. Refs: openclaw/openclaw#44884 Gap 7 (High TLS enforcement): Add startup-security-checks.ts for network-exposure safety checks at startup. Refs: openclaw/openclaw#44884 Gap 8 (Medium auto HSTS): Auto-inject HSTS when TLS is active. Refs: openclaw/openclaw#44884 Gap 9 (Medium bind safety): Bind-all-interfaces detection via startup checks. Refs: openclaw/openclaw#44884 Gaps 3, 5, 10 already fixed in fork — no changes needed.
…audit Gap 1 (Critical CWE-208): Replace !== with safeEqualSecret() for TLS fingerprint comparison in client.ts, eliminating timing side-channel attacks on WebSocket and HTTP TLS pinning. Refs: openclaw/openclaw#49083 Gap 2 (High revocation race): Add sync invalidated flag on GatewayClient, set before respond() in device.token.rotate/revoke and device.pair.remove handlers, with per-RPC dispatch guard in message-handler to reject pipelined RPCs from revoked credentials. Refs: openclaw/openclaw#70707 Gap 4 (High unbounded sessions): Add authenticated-connection-budget.ts per-device connection cap (default 8) with env override. Refs: openclaw/openclaw#59842 Gap 6 (High HTTP flood): Add request-rate-limit.ts sliding-window per-IP HTTP request rate limiter (default 120/min) for REST endpoints. Refs: openclaw/openclaw#44884 Gap 7 (High TLS enforcement): Add startup-security-checks.ts for network-exposure safety checks at startup. Refs: openclaw/openclaw#44884 Gap 8 (Medium auto HSTS): Auto-inject HSTS when TLS is active. Refs: openclaw/openclaw#44884 Gap 9 (Medium bind safety): Bind-all-interfaces detection via startup checks. Refs: openclaw/openclaw#44884 Gaps 3, 5, 10 already fixed in fork — no changes needed.
…audit Gap 1 (Critical CWE-208): Replace !== with safeEqualSecret() for TLS fingerprint comparison in client.ts, eliminating timing side-channel attacks on WebSocket and HTTP TLS pinning. Refs: openclaw/openclaw#49083 Gap 2 (High revocation race): Add sync invalidated flag on GatewayClient, set before respond() in device.token.rotate/revoke and device.pair.remove handlers, with per-RPC dispatch guard in message-handler to reject pipelined RPCs from revoked credentials. Refs: openclaw/openclaw#70707 Gap 4 (High unbounded sessions): Add authenticated-connection-budget.ts per-device connection cap (default 8) with env override. Refs: openclaw/openclaw#59842 Gap 6 (High HTTP flood): Add request-rate-limit.ts sliding-window per-IP HTTP request rate limiter (default 120/min) for REST endpoints. Refs: openclaw/openclaw#44884 Gap 7 (High TLS enforcement): Add startup-security-checks.ts for network-exposure safety checks at startup. Refs: openclaw/openclaw#44884 Gap 8 (Medium auto HSTS): Auto-inject HSTS when TLS is active. Refs: openclaw/openclaw#44884 Gap 9 (Medium bind safety): Bind-all-interfaces detection via startup checks. Refs: openclaw/openclaw#44884 Gaps 3, 5, 10 already fixed in fork — no changes needed.
…audit Gap 1 (Critical CWE-208): Replace !== with safeEqualSecret() for TLS fingerprint comparison in client.ts, eliminating timing side-channel attacks on WebSocket and HTTP TLS pinning. Refs: openclaw/openclaw#49083 Gap 2 (High revocation race): Add sync invalidated flag on GatewayClient, set before respond() in device.token.rotate/revoke and device.pair.remove handlers, with per-RPC dispatch guard in message-handler to reject pipelined RPCs from revoked credentials. Refs: openclaw/openclaw#70707 Gap 4 (High unbounded sessions): Add authenticated-connection-budget.ts per-device connection cap (default 8) with env override. Refs: openclaw/openclaw#59842 Gap 6 (High HTTP flood): Add request-rate-limit.ts sliding-window per-IP HTTP request rate limiter (default 120/min) for REST endpoints. Refs: openclaw/openclaw#44884 Gap 7 (High TLS enforcement): Add startup-security-checks.ts for network-exposure safety checks at startup. Refs: openclaw/openclaw#44884 Gap 8 (Medium auto HSTS): Auto-inject HSTS when TLS is active. Refs: openclaw/openclaw#44884 Gap 9 (Medium bind safety): Bind-all-interfaces detection via startup checks. Refs: openclaw/openclaw#44884 Gaps 3, 5, 10 already fixed in fork — no changes needed.
…audit Gap 1 (Critical CWE-208): Replace !== with safeEqualSecret() for TLS fingerprint comparison in client.ts, eliminating timing side-channel attacks on WebSocket and HTTP TLS pinning. Refs: openclaw/openclaw#49083 Gap 2 (High revocation race): Add sync invalidated flag on GatewayClient, set before respond() in device.token.rotate/revoke and device.pair.remove handlers, with per-RPC dispatch guard in message-handler to reject pipelined RPCs from revoked credentials. Refs: openclaw/openclaw#70707 Gap 4 (High unbounded sessions): Add authenticated-connection-budget.ts per-device connection cap (default 8) with env override. Refs: openclaw/openclaw#59842 Gap 6 (High HTTP flood): Add request-rate-limit.ts sliding-window per-IP HTTP request rate limiter (default 120/min) for REST endpoints. Refs: openclaw/openclaw#44884 Gap 7 (High TLS enforcement): Add startup-security-checks.ts for network-exposure safety checks at startup. Refs: openclaw/openclaw#44884 Gap 8 (Medium auto HSTS): Auto-inject HSTS when TLS is active. Refs: openclaw/openclaw#44884 Gap 9 (Medium bind safety): Bind-all-interfaces detection via startup checks. Refs: openclaw/openclaw#44884 Gaps 3, 5, 10 already fixed in fork — no changes needed.
…audit Gap 1 (Critical CWE-208): Replace !== with safeEqualSecret() for TLS fingerprint comparison in client.ts, eliminating timing side-channel attacks on WebSocket and HTTP TLS pinning. Refs: openclaw/openclaw#49083 Gap 2 (High revocation race): Add sync invalidated flag on GatewayClient, set before respond() in device.token.rotate/revoke and device.pair.remove handlers, with per-RPC dispatch guard in message-handler to reject pipelined RPCs from revoked credentials. Refs: openclaw/openclaw#70707 Gap 4 (High unbounded sessions): Add authenticated-connection-budget.ts per-device connection cap (default 8) with env override. Refs: openclaw/openclaw#59842 Gap 6 (High HTTP flood): Add request-rate-limit.ts sliding-window per-IP HTTP request rate limiter (default 120/min) for REST endpoints. Refs: openclaw/openclaw#44884 Gap 7 (High TLS enforcement): Add startup-security-checks.ts for network-exposure safety checks at startup. Refs: openclaw/openclaw#44884 Gap 8 (Medium auto HSTS): Auto-inject HSTS when TLS is active. Refs: openclaw/openclaw#44884 Gap 9 (Medium bind safety): Bind-all-interfaces detection via startup checks. Refs: openclaw/openclaw#44884 Gaps 3, 5, 10 already fixed in fork — no changes needed.
…audit Gap 1 (Critical CWE-208): Replace !== with safeEqualSecret() for TLS fingerprint comparison in client.ts, eliminating timing side-channel attacks on WebSocket and HTTP TLS pinning. Refs: openclaw/openclaw#49083 Gap 2 (High revocation race): Add sync invalidated flag on GatewayClient, set before respond() in device.token.rotate/revoke and device.pair.remove handlers, with per-RPC dispatch guard in message-handler to reject pipelined RPCs from revoked credentials. Refs: openclaw/openclaw#70707 Gap 4 (High unbounded sessions): Add authenticated-connection-budget.ts per-device connection cap (default 8) with env override. Refs: openclaw/openclaw#59842 Gap 6 (High HTTP flood): Add request-rate-limit.ts sliding-window per-IP HTTP request rate limiter (default 120/min) for REST endpoints. Refs: openclaw/openclaw#44884 Gap 7 (High TLS enforcement): Add startup-security-checks.ts for network-exposure safety checks at startup. Refs: openclaw/openclaw#44884 Gap 8 (Medium auto HSTS): Auto-inject HSTS when TLS is active. Refs: openclaw/openclaw#44884 Gap 9 (Medium bind safety): Bind-all-interfaces detection via startup checks. Refs: openclaw/openclaw#44884 Gaps 3, 5, 10 already fixed in fork — no changes needed.
Summary
device.token.rotate,device.token.revoke, anddevice.pair.removerespond 200 OK then deferdisconnectClientsForDeviceviaqueueMicrotask. RPCs already pipelined in the WS buffer land with the rotated/revoked token before the socket closes.invalidatedflag onGatewayWsClient, set beforerespond()in all three handlers. Added a per-RPC dispatch guard that force-closes flagged clients. Introducedcontext.invalidateClientsForDevice()as a sync companion to the existing async disconnect. Defense-in-depth:disconnectClientsForDevicenow also sets the flag.message-handler.ts:1444-1458), disconnect scheduling (stillqueueMicrotask), admin response flushing behavior.Change Type (select all)
Scope (select all touched areas)
Linked Issue/PR
Root Cause (if applicable)
queueMicrotaskdeferral of socket close created a window where the rotated/revoked token was still accepted. No per-RPC re-check existed for device-token auth (only for shared-auth).message-handler.ts:1444-1458); device-token auth was assumed to be covered by socket close, but socket close is async.Regression Test Plan (if applicable)
invalidateClientsForDevice()are rejected;invalidatedflag is set beforerespond()returns.User-visible / Behavior Changes
RPCs arriving on a device-token WS connection after token rotation/revocation are now rejected immediately instead of being processed until socket close completes.
Diagram (if applicable)
Security Impact (required)
invalidatedflag is a new in-memory gate on RPC dispatch. Risk is false-positive invalidation; mitigated by setting the flag only in the three explicit revocation handlers and indisconnectClientsForDevice(which already terminates the connection).Repro + Verification
Environment
Steps
device.token.rotatefrom adminExpected
Pipelined RPCs are rejected after rotation.
Actual (before fix)
Pipelined RPCs execute with the rotated token until
queueMicrotaskfires socket close.Evidence
Human Verification (required)
disconnectClientsForDevicealso sets flag (defense-in-depth); idempotent close on already-closed socketsReview Conversations
Compatibility / Migration
Risks and Mitigations
invalidatedflag introduces a new code path in the hot RPC dispatch loop.sharedGatewayAuthguard pattern.