Skip to content

fix(gateway): block webchat session compaction mutations#70716

Merged
drobison00 merged 2 commits intoopenclaw:mainfrom
drobison00:sessions-webchat-guard
Apr 23, 2026
Merged

fix(gateway): block webchat session compaction mutations#70716
drobison00 merged 2 commits intoopenclaw:mainfrom
drobison00:sessions-webchat-guard

Conversation

@drobison00
Copy link
Copy Markdown
Contributor

fix(gateway): block webchat session compaction mutations

Summary

Describe the problem and fix in 2-5 bullets:

  • Problem: WEBCHAT_UI clients were blocked from sessions.patch and sessions.delete, but the sibling mutation handlers sessions.compact and sessions.compaction.restore still ran.
  • Why it matters: Those handlers rewrite or restore persisted session history, so the webchat-specific mutation boundary was incomplete.
  • What changed: Applied rejectWebchatSessionMutation(...) to sessions.compact and sessions.compaction.restore, and expanded the existing gateway regression test to cover both handlers.
  • What did NOT change (scope boundary): No method-scope changes, no control-ui policy changes, and no changes outside the gateway session handler plus its targeted test.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes
  • Related NVIDIA-dev/openclaw-tracking#501
  • This PR fixes a bug or regression

Root Cause (if applicable)

  • Root cause: The webchat session-mutation helper was only wired into sessions.patch and sessions.delete, leaving the sibling compact and restore mutation paths unguarded.
  • Missing detection / guardrail: The existing gateway regression coverage only asserted webchat rejection for patch and delete, so the sibling omission was not locked down.
  • Contributing context (if known): The affected handlers already live in the same admin-sensitive session-mutation family, which made the missing guard a consistency gap rather than a separate policy design.

Regression Test Plan (if applicable)

For bug fixes or regressions, name the smallest reliable test coverage that should catch this. Otherwise write N/A.

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: src/gateway/server.sessions.gateway-server-sessions-a.test.ts
  • Scenario the test should lock in: A WEBCHAT_UI client cannot patch, delete, compact, or restore sessions, even when the client otherwise has admin-scoped access.
  • Why this is the smallest reliable guardrail: The gateway test exercises the real RPC handlers and their webchat client classification without requiring broader end-to-end setup.
  • Existing test that already covers this (if any): The same file already covered patch and delete rejection for webchat clients.
  • If no new test is added, why not: N/A

User-visible / Behavior Changes

  • WEBCHAT_UI clients now receive the same invalid-request rejection for sessions.compact and sessions.compaction.restore that already applied to sessions.patch and sessions.delete.
  • Control UI behavior is unchanged.

Diagram (if applicable)

Before:
[WEBCHAT_UI client] -> [sessions.compact / sessions.compaction.restore] -> [mutation allowed]

After:
[WEBCHAT_UI client] -> [rejectWebchatSessionMutation] -> [invalid request error]

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? No
  • Data access scope changed? No
  • If any Yes, explain risk + mitigation: N/A

Repro + Verification

Environment

  • OS: Linux 6.8.0-110-generic x86_64
  • Runtime/container: Node.js v22.14.0
  • Model/provider: N/A
  • Integration/channel (if any): Gateway WEBCHAT_UI
  • Relevant config (redacted): N/A

Steps

  1. Start the gateway session test harness with a WEBCHAT_UI client connection.
  2. Issue sessions.compact and sessions.compaction.restore RPC requests against an existing session and checkpoint.
  3. Run pnpm test:gateway -- src/gateway/server.sessions.gateway-server-sessions-a.test.ts.

Expected

  • The webchat client is rejected for patch, delete, compact, and restore session mutations.

Actual

  • The targeted gateway test file passed with the new compact and restore rejection assertions in place.

Evidence

Attach at least one:

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Validation command run:

pnpm test:gateway -- src/gateway/server.sessions.gateway-server-sessions-a.test.ts

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios: Reviewed the handler diff to confirm only sessions.compact and sessions.compaction.restore gained the existing webchat guard; ran pnpm test:gateway -- src/gateway/server.sessions.gateway-server-sessions-a.test.ts; confirmed the branch diff only touches the session handler and its regression test.
  • Edge cases checked: Existing patch/delete webchat rejection remains covered in the expanded test; Control UI exemption remains unchanged in the shared helper.
  • What you did not verify: Manual end-to-end gateway traffic outside the existing automated gateway test harness.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? No
  • Migration needed? No
  • If yes, exact upgrade steps: N/A

Risks and Mitigations

  • Risk: A non-control webchat client that previously relied on compact or restore will now be rejected.
    • Mitigation: This aligns those handlers with the existing webchat restriction already enforced for the sibling patch and delete mutations.

@openclaw-barnacle openclaw-barnacle Bot added gateway Gateway runtime size: S maintainer Maintainer-authored PR labels Apr 23, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 23, 2026

Greptile Summary

This PR extends the existing rejectWebchatSessionMutation guard to sessions.compact and sessions.compaction.restore, closing a consistency gap where WEBCHAT_UI clients were already blocked from sessions.patch and sessions.delete but not from the sibling compaction mutation handlers. The change is minimal and surgical — the union type on action is widened, the two handlers get the guard inserted in the same position as the existing guards, and the regression test is expanded with a proper checkpoint fixture to cover both new rejection paths.

Confidence Score: 5/5

Safe to merge — the change is a targeted, consistent extension of an existing guard with matching test coverage.

All findings are at most P2. The fix is consistent with the existing pattern, the error messages match the test assertions, and the createCheckpointFixture helper is a pre-existing utility already used in adjacent tests. No logic, security, or API-contract issues were found.

No files require special attention.

Reviews (1): Last reviewed commit: "fix(gateway): block webchat session comp..." | Re-trigger Greptile

drobison00 added a commit to drobison00/openclaw that referenced this pull request Apr 23, 2026
@drobison00 drobison00 force-pushed the sessions-webchat-guard branch from a0db036 to 52a7428 Compare April 23, 2026 18:46
@aisle-research-bot
Copy link
Copy Markdown

aisle-research-bot Bot commented Apr 23, 2026

🔒 Aisle Security Analysis

We found 1 potential security issue(s) in this PR:

# Severity Title
1 🟠 High Webchat session-mutation guard bypass via spoofed client.id (CONTROL_UI) while in webchat mode
1. 🟠 Webchat session-mutation guard bypass via spoofed client.id (CONTROL_UI) while in webchat mode
Property Value
Severity High
CWE CWE-287
Location src/gateway/server-methods/sessions.ts:231-236

Description

The rejectWebchatSessionMutation() guard is intended to block session mutations (patch/delete/compact/restore) for webchat clients, but it can be bypassed by spoofing the connect.client.id field.

  • Webchat classification (isWebchatConnect) is derived from client-controlled connect params and returns true if client.mode === "webchat" OR client.id === "webchat-ui" (see isWebchatClient).
  • rejectWebchatSessionMutation() allows the mutation if client.connect.client.id === CONTROL_UI.
  • Therefore a malicious webchat client can send connect params with client.mode: "webchat" and client.id: "openclaw-control-ui".
    • isWebchatConnect() returns true (because mode is webchat)
    • the guard then hits the CONTROL_UI exception and returns false (no rejection)
    • session mutation proceeds, defeating the new protections for compact and restore (and existing patch/delete).

Vulnerable code:

if (!params.client?.connect || !params.isWebchatConnect(params.client.connect)) {
  return false;
}
if (params.client.connect.client.id === GATEWAY_CLIENT_IDS.CONTROL_UI) {
  return false;
}

This is an authorization bypass because connect.client.id/mode originate from the client handshake and are not a trustworthy basis for privileged exceptions.

Recommendation

Treat connect.client.* as untrusted metadata and do not use it for security decisions unless it is cryptographically/assertively bound to the connection.

Concrete fixes (pick one):

  1. Remove the CONTROL_UI exception entirely (simplest, safest).

  2. If an exception is required, ensure the client is actually an operator UI by enforcing consistency:

    • Normalize and validate that client.mode === "ui" (or non-webchat) and client.id === CONTROL_UI before exempting.
    • Do not exempt any client whose mode is webchat.

Example safer implementation:

import { GATEWAY_CLIENT_MODES, normalizeGatewayClientMode, normalizeGatewayClientId } from "../protocol/client-info.js";

const mode = normalizeGatewayClientMode(params.client.connect.client.mode);
const id = normalizeGatewayClientId(params.client.connect.client.id);

if (!params.isWebchatConnect(params.client.connect)) return false;// Never exempt webchat-mode clients.
if (mode === GATEWAY_CLIENT_MODES.WEBCHAT) {
  params.respond(false, undefined, errorShape(...));
  return true;
}// (Optional) exempt only real control UI mode.
if (id === GATEWAY_CLIENT_IDS.CONTROL_UI && mode === GATEWAY_CLIENT_MODES.UI) return false;

Also consider moving “client type” classification to server-side signals (origin checks, authenticated role/scopes, or a server-issued client attestation) rather than connect-declared fields.


Analyzed PR: #70716 at commit 52a7428

Last updated on: 2026-04-23T18:51:31Z

@drobison00 drobison00 merged commit 873dce1 into openclaw:main Apr 23, 2026
68 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gateway Gateway runtime maintainer Maintainer-authored PR size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant