Skip to content

fix(gateway): redact fast-path console logs#76306

Merged
steipete merged 2 commits into
openclaw:mainfrom
rubencu:codex/redact-gateway-console
May 10, 2026
Merged

fix(gateway): redact fast-path console logs#76306
steipete merged 2 commits into
openclaw:mainfrom
rubencu:codex/redact-gateway-console

Conversation

@rubencu

@rubencu rubencu commented May 2, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Problem: pnpm gateway:watch:raw / foreground openclaw gateway could print WhatsApp/libsignal session objects from dependency console.* calls before OpenClaw installed console capture.
  • Why it matters: those objects include session material fields such as ratchet/root/private key data, so raw gateway terminal logs could expose secrets.
  • What changed: the Gateway foreground fast path installs console capture before program.parseAsync(...), and known libsignal session-dump prefixes are suppressed before verbose-mode passthrough.
  • What did NOT change (scope boundary): no WhatsApp protocol behavior, dependency versions, auth semantics, config surface, CLI flags, or Gateway networking behavior changed.

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 #
  • This PR fixes a bug or regression

Real behavior proof (required for external PRs)

  • Behavior or issue addressed: foreground Gateway startup previously let dependency console.info("Closing session:", session) output reach the terminal before console capture/redaction was installed.
  • Real environment tested: macOS source checkout, Node via repo scripts/run-node.mjs, isolated HOME and OPENCLAW_HOME, live Gateway on loopback with token auth and /healthz probe.
  • Exact steps or command run after this patch: node /tmp/openclaw-pr76306-gateway-proof.mjs /Users/rubencu/workplace/openclaw-redact-gateway-console pr-head expect-suppressed
  • Evidence after fix (screenshot, recording, terminal capture, console output, redacted runtime log, linked artifact, or copied live output):
{
  "label": "pr-head",
  "cwd": "/Users/rubencu/workplace/openclaw-redact-gateway-console",
  "port": 37437,
  "health": "{\"ok\":true,\"status\":\"live\"}",
  "expected": "expect-suppressed",
  "leakedPrefix": false,
  "leakedSecret": false,
  "leakExcerpt": "",
  "exit": { "code": 130, "signal": null },
  "outputTail": "2026-05-09T22:36:08.181-04:00 [gateway] ready\n2026-05-09T22:36:08.187-04:00 [heartbeat] started\n2026-05-09T22:36:11.236-04:00 [shutdown] completed cleanly in 16ms"
}
  • Observed result after fix: the same live Gateway process reached {"ok":true,"status":"live"}, then the injected libsignal-shaped dependency console output was absent from terminal capture (leakedPrefix=false, leakedSecret=false).

Additional live WhatsApp gateway:watch proof on PR head:

{
  "command": "node scripts/watch-node.mjs gateway --force --verbose",
  "config": "normal local OpenClaw config with WhatsApp account; raw output monitored with numbers redacted",
  "health": { "ok": true, "status": "live" },
  "whatsappEvidence": "sessionKey=agent:main:whatsapp:direct:[number] entered processing, then outbound WhatsApp echo was skipped after reply delivery",
  "sensitivePrefix": 0,
  "sensitiveField": 0,
  "checkedPrefixes": ["Closing session:", "Opening session:", "Removing old closed session:", "Session already closed", "Session already open"],
  "checkedFields": ["currentRatchet", "ephemeralKeyPair", "privKey", "rootKey", "baseKey", "remoteIdentityKey"]
}

Observed result: the PR-head gateway:watch process loaded WhatsApp, listened for personal inbound messages, processed a live WhatsApp direct message, sent a reply, skipped the outbound echo, and did not emit any known libsignal session-dump prefix or key-field line in terminal output or the active file log.

  • What was not tested: forced real WhatsApp session rotation was not induced, to avoid intentionally exposing real session key material on the pre-fix branch. The PR head was additionally tested with a real WhatsApp direct-message turn through gateway:watch, with log monitoring limited to redacted counters.
  • Before evidence (optional but encouraged):
{
  "label": "main-rerun",
  "cwd": "/tmp/openclaw-pr76306-main-live",
  "base": "origin/main@8e8f7915b2573b355d514bd8bebf6a502913c2ab",
  "health": "{\"ok\":true,\"status\":\"live\"}",
  "expected": "expect-leak",
  "leakedPrefix": true,
  "leakedSecret": true,
  "leakExcerpt": "Closing session: {\n  currentRatchet: {\n    rootKey: '<FAKE_SECRET>',\n    ephemeralKeyPair: { privKey: '<FAKE_SECRET>' }\n  },\n  indexInfo: {\n    baseKey: '<FAKE_SECRET>',\n    closed: -1\n  },\n  privKey: '<FAKE_SECRET>'\n}\n2026-05-09T22:34:32.940-04:00 [gateway] ready"
}

Root Cause (if applicable)

  • Root cause: runCli(...) returns from the Gateway foreground fast path after tryRunGatewayRunFastPath(...), while the normal CLI enableConsoleCapture() call lives later in the non-fast-path startup path.
  • Missing detection / guardrail: tests covered generic console redaction once capture was installed, but did not assert that the fast path installs capture before command parsing, and did not cover libsignal prefix suppression while verbose mode is enabled.
  • Contributing context (if known): the currently installed node_modules/libsignal/src/session_record.js logs Closing session:, Opening session:, and Removing old closed session: with session objects.

Regression Test Plan (if applicable)

  • 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/cli/run-main.exit.test.ts, src/logging/console-capture.test.ts
  • Scenario the test should lock in: Gateway foreground fast path calls enableConsoleCapture() before program.parseAsync(...), and libsignal session-dump prefixes are suppressed even when verbose mode is enabled.
  • Why this is the smallest reliable guardrail: it validates the exact startup ordering bug and the exact sensitive dependency prefix behavior without requiring real WhatsApp session material in tests.
  • Existing test that already covers this (if any): existing console capture tests cover credential redaction and forwarding after capture is installed.
  • If no new test is added, why not: N/A

User-visible / Behavior Changes

Raw Gateway watch/foreground logs no longer print known WhatsApp/libsignal session-object dumps. Normal Gateway and WhatsApp behavior is unchanged.

Diagram (if applicable)

Before:
gateway fast path -> parse command -> dependency console output can reach terminal before capture

After:
gateway fast path -> enable console capture -> parse command -> sensitive dependency session dumps suppressed

Security Impact (required)

  • New permissions/capabilities? (Yes/No) No
  • Secrets/tokens handling changed? (Yes/No) Yes
  • New/changed network calls? (Yes/No) No
  • Command/tool execution surface changed? (Yes/No) No
  • Data access scope changed? (Yes/No) No
  • If any Yes, explain risk + mitigation: this reduces exposure of WhatsApp/libsignal session key material in raw Gateway terminal logs. It does not add access to secrets; it prevents known sensitive dependency console dumps from being emitted.

Repro + Verification

Environment

  • OS: macOS
  • Runtime/container: Node + pnpm source checkout
  • Model/provider: N/A
  • Integration/channel (if any): Gateway foreground/raw watch logging, WhatsApp/libsignal dependency output, live WhatsApp direct-message path
  • Relevant config (redacted): isolated proof HOME and OPENCLAW_HOME; loopback Gateway token auth; no real WhatsApp secrets

Steps

  1. Rebase PR branch on origin/main@8e8f7915b2573b355d514bd8bebf6a502913c2ab and remove contributor CHANGELOG.md drift.
  2. Run live current-main proof with the Gateway process and a non-real libsignal-shaped session console emission.
  3. Run the same live proof on PR head 2d7b20064aa9b90c75287d9a16836b2f3f9f6f14.
  4. Run PR-head gateway:watch with the normal local WhatsApp config, send a live WhatsApp direct message, and monitor terminal/file-log counters for known libsignal dump prefixes and key-field names.
  5. Run targeted unit tests and checks.

Expected

  • Current main prints the dependency session dump in raw Gateway output.
  • PR head starts the Gateway and suppresses that dependency session dump, including in verbose mode.

Actual

  • Current main: live /healthz returned {"ok":true,"status":"live"} and terminal capture included Closing session: plus non-real session secret fields.
  • PR head: live /healthz returned {"ok":true,"status":"live"} and terminal capture reported leakedPrefix=false, leakedSecret=false.
  • PR head live WhatsApp: gateway:watch loaded WhatsApp, processed agent:main:whatsapp:direct:[number], sent an outbound reply, skipped the echo, and terminal/file-log counters stayed at sensitivePrefix=0, sensitiveField=0.

Evidence

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

Human Verification (required)

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

  • Verified scenarios:
    • pnpm docs:list
    • pnpm install after rebase to refresh current dependency tree
    • node /tmp/openclaw-pr76306-gateway-proof.mjs /tmp/openclaw-pr76306-main-live main-rerun expect-leak
    • node /tmp/openclaw-pr76306-gateway-proof.mjs /Users/rubencu/workplace/openclaw-redact-gateway-console pr-head expect-suppressed
    • PR-head node scripts/watch-node.mjs gateway --force --verbose with normal local WhatsApp config; processed a live WhatsApp direct-message turn; terminal/file-log counters stayed sensitivePrefix=0, sensitiveField=0
    • pnpm test src/cli/run-main.exit.test.ts src/logging/console-capture.test.ts
    • pnpm exec oxfmt --check --threads=1 src/cli/run-main.ts src/cli/run-main.exit.test.ts src/logging/console.ts src/logging/console-capture.test.ts
    • git diff --check
    • pnpm changed:lanes --json
    • codex review --base origin/main
  • Edge cases checked: verbose mode still suppresses known libsignal session-dump prefixes; Gateway fast path installs capture before parsing; CHANGELOG.md has no PR diff.
  • What you did not verify: full pnpm check / pnpm test broad suites locally; changed lanes are core prod + core tests, and broad validation is left to PR CI.

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/No) Yes
  • Config/env changes? (Yes/No) No
  • Migration needed? (Yes/No) No
  • If yes, exact upgrade steps: N/A

Risks and Mitigations

  • Risk: future libsignal wording changes could use a new prefix.
    • Mitigation: this patch covers the currently installed dependency prefixes confirmed in node_modules/libsignal/src/session_record.js; a future dependency wording change can add a narrow prefix follow-up.

@openclaw-barnacle openclaw-barnacle Bot added cli CLI command changes size: XS labels May 2, 2026
@clawsweeper

clawsweeper Bot commented May 2, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge.

Summary
The PR installs console capture before Gateway foreground fast-path parsing, suppresses known libsignal session-dump console prefixes before verbose passthrough, and adds focused regression tests.

Reproducibility: yes. Current-main source shows the Gateway foreground fast path parses before console capture and verbose mode bypasses prefix suppression, and the PR body includes copied before/after live Gateway output.

Real behavior proof
Sufficient (live_output): The PR body provides copied live Gateway output and redacted WhatsApp gateway:watch counters showing after-fix suppression in a real setup.

Next step before merge
The branch already has the focused fix, tests, and sufficient real behavior proof; the remaining action is maintainer review plus exact-head CI resolution, not an automated repair PR.

Security
Cleared: The diff reduces sensitive terminal log exposure and does not add dependencies, permissions, workflow changes, network calls, or new code-execution paths.

Review details

Best possible solution:

Land the scoped console-capture ordering and sensitive-prefix suppression fix after required CI is green or failures are confirmed unrelated, keeping the change limited to logging redaction.

Do we have a high-confidence way to reproduce the issue?

Yes. Current-main source shows the Gateway foreground fast path parses before console capture and verbose mode bypasses prefix suppression, and the PR body includes copied before/after live Gateway output.

Is this the best way to solve the issue?

Yes. Installing capture at the fast-path boundary and checking sensitive prefixes before verbose passthrough is the narrowest maintainable fix without changing WhatsApp protocol behavior, dependencies, auth, config, or networking.

Acceptance criteria:

  • pnpm test src/cli/run-main.exit.test.ts src/logging/console-capture.test.ts
  • pnpm exec oxfmt --check --threads=1 src/cli/run-main.ts src/cli/run-main.exit.test.ts src/logging/console.ts src/logging/console-capture.test.ts
  • Resolve or confirm unrelated the failing exact-head CI check runs for 2d7b200

What I checked:

  • Current main fast path misses console capture: On current main, tryRunGatewayRunFastPath builds the Gateway command and calls program.parseAsync(argv) without importing or calling enableConsoleCapture, so the fast path can return before the normal CLI capture setup. (src/cli/run-main.ts:185, 4e09538f4424)
  • Current main verbose mode bypasses sensitive-prefix suppression: shouldSuppressConsoleMessage returns false immediately in verbose mode before checking the suppressed libsignal-style prefixes. (src/logging/console.ts:151, 4e09538f4424)
  • Pinned dependency emits the affected session prefixes: The lockfile pins @whiskeysockets/libsignal-node to commit 1c30d7d7e76a3b0aa120b04dc6a26f5a12dccf67, whose session_record.js emits Closing session:, Opening session:, and Removing old closed session: with session objects. (pnpm-lock.yaml:4783, 4e09538f4424)
  • PR diff applies the narrow runtime fix: The PR imports enableConsoleCapture in the Gateway fast-path import set, calls it before program.parseAsync(argv), and moves prefix suppression before verbose-mode passthrough. (src/cli/run-main.ts:184, 2d7b20064aa9)
  • PR diff adds focused regression coverage: The diff adds a fast-path ordering test and a verbose-mode libsignal suppression test covering the reported leak path. (src/cli/run-main.exit.test.ts:331, 2d7b20064aa9)
  • Contributor proof shows before/after live behavior: The PR body includes copied live Gateway output where current main leaked an injected libsignal-shaped session object, while PR head reached /healthz and reported leakedPrefix=false and leakedSecret=false; it also includes a live WhatsApp gateway:watch pass with zero sensitive-prefix and key-field counters. (2d7b20064aa9)

Likely related people:

  • steipete: Commit history shows perf: fast-path gateway foreground startup introduced tryRunGatewayRunFastPath, with later nearby CLI startup and exit-test maintenance. (role: gateway fast-path introducer and adjacent CLI contributor; confidence: high; commits: 955f0a692a38, 0c50957dbb96, bee3a7372e73; files: src/cli/run-main.ts, src/cli/run-main.exit.test.ts)
  • vincentkoc: Recent path history shows CLI fast-path changes in src/cli/run-main.ts and console/file sink redaction work in src/logging/console.ts, both central to this PR. (role: recent CLI startup and logging contributor; confidence: high; commits: e855b9c8d926, 6811ef058b49, 4cba24a4c352; files: src/cli/run-main.ts, src/logging/console.ts, src/logging/console-capture.test.ts)

Remaining risk / open question:

  • Exact-head CI still has failing node check shards that must be resolved or confirmed unrelated before merge.
  • The suppression list covers the currently pinned libsignal wording; future upstream prefix wording changes may need a narrow follow-up.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 4e09538f4424.

@rubencu rubencu force-pushed the codex/redact-gateway-console branch 3 times, most recently from afde59d to 2d7b200 Compare May 10, 2026 02:44
@openclaw-barnacle openclaw-barnacle Bot added the proof: supplied External PR includes structured after-fix real behavior proof. label May 10, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 10, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 10, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 10, 2026
@steipete steipete force-pushed the codex/redact-gateway-console branch from 2d7b200 to f864f8e Compare May 10, 2026 03:50
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 10, 2026
@steipete steipete merged commit 4f053b8 into openclaw:main May 10, 2026
113 checks passed
@steipete

Copy link
Copy Markdown
Contributor

Landed via rebase onto main.

Verification:

  • pnpm test src/cli/run-main.exit.test.ts src/logging/console-capture.test.ts src/cli/command-registration-policy.test.ts
  • pnpm exec oxfmt --check --threads=1 CHANGELOG.md src/cli/run-main.ts src/cli/run-main.exit.test.ts src/logging/console.ts src/logging/console-capture.test.ts
  • git diff --check
  • pnpm changed:lanes --json -> core + coreTests + docs
  • Exact-head PR CI on f864f8eb5040df0eede2866f9c3ca0320c046cd1: no failures; core/node shards green before merge. One non-surface CodeQL Critical Quality network-runtime shard was still in progress at merge.

Thanks @rubencu!

longstoryscott pushed a commit to longstoryscott/openclaw that referenced this pull request May 13, 2026
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 24, 2026
jameslcowan pushed a commit to jameslcowan/openclaw that referenced this pull request Jun 2, 2026
sablehead pushed a commit to sablehead/openclaw that referenced this pull request Jun 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cli CLI command changes proof: supplied External PR includes structured after-fix real behavior proof. size: XS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants