Skip to content

Cherry-pick batch: Gateway fixes and improvements (2/2) (50 commits)#1959

Merged
alexey-pelykh merged 48 commits intomainfrom
staging/cherry-pick-1870
Mar 24, 2026
Merged

Cherry-pick batch: Gateway fixes and improvements (2/2) (50 commits)#1959
alexey-pelykh merged 48 commits intomainfrom
staging/cherry-pick-1870

Conversation

@alexey-pelykh
Copy link
Copy Markdown

Cherry-pick batch from upstream

Issue: #1870
Commits: 38 cherry-picked, 12 skipped (already applied in prior batches)

See issue for full commit list.

Closes #1870

🤖 Generated with Claude Code

steipete and others added 30 commits March 24, 2026 02:52
Prevents crash when totals is undefined in byModel/byProvider/byAgent
sort comparators. Fixes 'Cannot read properties of undefined (reading
totalTokens)' crash that causes context overflow in active sessions.

(cherry picked from commit 6921716)
The revert of openclaw#43478 (commit 39b4185) was silently undone by
3704293 which was based on a branch that included the original
change. This removes the auth.mode=none skipPairing condition again.

The blanket skip was too broad - it disabled pairing for ALL websocket
clients, not just Control UI behind reverse proxies.

(cherry picked from commit 92fc806)
Fixes openclaw#42931

When gateway.auth.mode is set to "none", authentication succeeds with
method "none" but sharedAuthOk remains false because the auth-context
only recognises token/password/trusted-proxy methods. This causes all
pairing-skip conditions to fail, so Control UI browser connections get
closed with code 1008 "pairing required" despite auth being disabled.

Short-circuit the skipPairing check: if the operator explicitly
disabled authentication, device pairing (which is itself an auth
mechanism) must also be bypassed.

Fixes openclaw#42931

(cherry picked from commit 9bffa34)
Plugin subagent dispatch used a hardcoded synthetic client carrying
operator.admin, operator.approvals, and operator.pairing for all
runtime.subagent.* calls. Plugin HTTP routes with auth:"plugin" require
no gateway auth by design, so an unauthenticated external request could
drive admin-only gateway methods (sessions.delete, agent.run) through
the subagent runtime.

Propagate the real gateway client into the plugin runtime request scope
when one is available. Plugin HTTP routes now run inside a scoped
runtime client: auth:"plugin" routes receive a non-admin synthetic
operator.write client; gateway-authenticated routes retain admin-capable
scopes. The security boundary is enforced at the HTTP handler level.

Fixes GHSA-xw77-45gv-p728

(cherry picked from commit a1520d7)
* test(gateway): stabilize suite session-store config

* test(gateway): preserve seeded config semantics

* test(gateway): update seeded session store overrides

(cherry picked from commit ad24fcc)
(cherry picked from commit b72ac79)
(cherry picked from commit ba34266)
device.token.rotate accepted attacker-controlled scopes and forwarded
them to rotateDeviceToken without verifying the caller held those
scopes. A pairing-scoped token could rotate up to operator.admin on
any already-paired device whose approvedScopes included admin.

Add a caller-scope subsetting check before rotateDeviceToken: the
requested scopes must be a subset of client.connect.scopes via the
existing roleScopesAllow helper. Reject with missing scope: <scope>
if not.

Also add server.device-token-rotate-authz.test.ts covering both the
priv-esc path and the admin-to-node-invoke chain.

Fixes GHSA-4jpw-hj22-2xmc

(cherry picked from commit dafd61b)
steipete and others added 17 commits March 24, 2026 03:16
In trusted-proxy mode, enforceOriginCheckForAnyClient was set to false
whenever proxy headers were present. This allowed browser-originated
WebSocket connections from untrusted origins to bypass origin validation
entirely, as the check only ran for control-ui and webchat client types.

An attacker serving a page from an untrusted origin could connect through
a trusted reverse proxy, inherit proxy-injected identity, and obtain
operator.admin access via the sharedAuthOk / roleCanSkipDeviceIdentity
path without any origin restriction.

Remove the hasProxyHeaders exemption so origin validation runs for all
browser-originated connections regardless of how the request arrived.

Fixes GHSA-5wcw-8jjv-m286

(cherry picked from commit ebed3bb)
* Gateway: tighten preauth handshake limits

* Changelog: note WebSocket preauth hardening

* Gateway: count preauth frame bytes accurately

* Gateway: cap WebSocket payloads before auth

(cherry picked from commit eff0d5a)
@alexey-pelykh alexey-pelykh enabled auto-merge (squash) March 24, 2026 02:30
@alexey-pelykh alexey-pelykh merged commit 91d9f89 into main Mar 24, 2026
7 checks passed
@alexey-pelykh alexey-pelykh deleted the staging/cherry-pick-1870 branch March 24, 2026 02:43
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.

Cherry-pick: Gateway fixes and improvements (2/2) (50 commits)

9 participants