openclaw - ✅(Solved) Fix fix(logging): subsystem console writes secrets verbatim at writeConsoleLine exit [2 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#73284Fetched 2026-04-29 06:21:29
View on GitHub
Comments
0
Participants
1
Timeline
7
Reactions
0
Author
Participants
Timeline (top)
cross-referenced ×3referenced ×3closed ×1

Error Message

  • Pass redacted to sink.error, sink.warn, and sink.log. This covers all subsystem console paths (trace/debug/info/warn/error/fatal and .raw()) because they share the same writeConsoleLine() exit.

Root Cause

This covers all subsystem console paths (trace/debug/info/warn/error/fatal and .raw()) because they share the same writeConsoleLine() exit.

Fix Action

Fix / Workaround

File logging for subsystem loggers was fixed by #67953 via the getChildLogger()buildLogger() file transport redactSensitiveText() gate. Console capture output was also fixed via the console.ts stdout/stderr gate.

However, createSubsystemLogger() writes directly through loggingState.rawConsole via writeConsoleLine(). That intentionally bypasses the patched console.ts capture handler to avoid recursion and preserve subsystem formatting, but it also bypasses redaction:

PR fix notes

PR #73309: fix(logging): redact secrets at subsystem console sink (#73284)

Description (problem / solution / changelog)

What

createSubsystemLogger() writes console output via writeConsoleLine() in src/logging/subsystem.ts, which deliberately bypasses the patched console.* capture handler in src/logging/console.ts to avoid recursion and preserve subsystem formatting. That bypass also skips the sink-boundary redactSensitiveText() gate that protects every other console exit, so any secret reaching a subsystem logger as a message string or formatted meta — sk-* keys, Bearer/Authorization values, PEM blocks — appears verbatim on the terminal.

This is a sub-issue of the umbrella tracked in #64046 and a direct follow-up to #67953, which fixed the same leak for the file transport.

Closes #73284.

Why this fix

Apply redactSensitiveText() at the writeConsoleLine() exit, immediately after the existing Windows surrogate sanitization and before dispatching to loggingState.rawConsole. This is the redact-at-sink-boundary pattern already used in:

  • console.ts:266 and console.ts:277 (patched stdout/stderr capture)
  • The file transport (#67953)

All subsystem console paths — trace/debug/info/warn/error/fatal and .raw() — share writeConsoleLine(), so this single change covers every level on every subsystem logger created by createSubsystemLogger() (and the children produced by .child()).

The fix is intentionally narrow:

  • One imported helper (redactSensitiveText from ./redact.js).
  • One redaction call between sanitization and sink dispatch.
  • A short comment explaining why the sink-boundary redaction has to live here, anchored to #73284 so it does not get refactored away.

Out-of-scope per the issue: raw JSONL sinks (raw-stream, config-audit, cron run logs, session transcript JSONL) are tracked separately under #64046 and are not touched here.

Tests

Added two cases in src/logging/subsystem.test.ts that reuse the existing installConsoleMethodSpy() helper:

  • A subsystem warn containing an sk- token: the secret is not present in the captured console arg, and the masked form (sk-sup…2345 or ***) is.
  • A subsystem error containing a Bearer <token>: the token body is not present in the captured console arg, while the literal "Bearer " prefix is preserved.

The existing installConsoleMethodSpy() already routes through loggingState.rawConsole, which is exactly the sink path the fix touches, so the assertions exercise the production code path end-to-end.

Notes

  • Single-area diff: src/logging/subsystem.ts, its test, and a one-line CHANGELOG entry under ## Unreleased ### Fixes with Thanks @edwin-rivera-dev.
  • No Plugin SDK or other-extension files touched. Pure core logging fix.
  • AI-assisted (Claude). Reviewed locally; please flag any oversight.

Validation

I have not run the full pnpm test/pnpm check:changed lanes locally for environment reasons, so I am relying on CI for the canonical proof. I have:

  • Mirrored the redact-at-sink-boundary pattern from src/logging/console.ts exactly, only adapting variable names to the subsystem path.
  • Confirmed the new tests use the same installConsoleMethodSpy() + setLoggerOverride() patterns as the surrounding suite, so the test isolation contract is unchanged.
  • Confirmed the CHANGELOG entry is single-line, anchored to a contributor (@edwin-rivera-dev), and references both the issue and the prior file-transport fix.

Happy to address any Greptile/Codex review feedback or extend coverage to additional patterns if reviewers want them.

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • src/logging/subsystem.test.ts (modified, +61/-2)
  • src/logging/subsystem.ts (modified, +22/-12)

PR #73325: fix(logging): redact subsystem console output

Description (problem / solution / changelog)

Summary

  • redact subsystem direct console output at the shared writeConsoleLine() sink exit
  • keep the existing Windows surrogate sanitization, then apply redactSensitiveText() before calling rawConsole / console
  • add regression coverage for .info(), .error(), and .raw() subsystem console paths

Fixes #73284 Follow-up to #67953 Part of #64046

Testing

  • node scripts/run-vitest.mjs run --config test/vitest/vitest.logging.config.ts src/logging/subsystem.test.ts
  • node scripts/run-vitest.mjs run --config test/vitest/vitest.logging.config.ts
  • pnpm check

AI assistance

AI-assisted. I reviewed the changes and ran the targeted logging test suite plus pnpm check.

Changed files

  • src/logging/subsystem.test.ts (modified, +46/-2)
  • src/logging/subsystem.ts (modified, +5/-3)

Code Example

createSubsystemLogger("gateway").info("token=sk-...")
writeConsoleLine()
    → rawConsole.log(sanitized)   ← no redaction

---

const redacted = redactSensitiveText(sanitized);
RAW_BUFFERClick to expand / collapse

Sub-issue of #64046

Follow-up to #67953 (file log redaction, now closed).

Problem

createSubsystemLogger() writes console/terminal output without redaction.

File logging for subsystem loggers was fixed by #67953 via the getChildLogger()buildLogger() file transport redactSensitiveText() gate. Console capture output was also fixed via the console.ts stdout/stderr gate.

However, createSubsystemLogger() writes directly through loggingState.rawConsole via writeConsoleLine(). That intentionally bypasses the patched console.ts capture handler to avoid recursion and preserve subsystem formatting, but it also bypasses redaction:

createSubsystemLogger("gateway").info("token=sk-...")
  → writeConsoleLine()
    → rawConsole.log(sanitized)   ← no redaction

Any secret reaching a subsystem logger as a message string or meta field can appear in plaintext on the terminal. This is a leak vector when terminal output is captured by CI logs, shared in screenshots, or collected by stdout/stderr forwarders.

Expected behavior

Apply redactSensitiveText() at the writeConsoleLine() sink exit, matching the sink-boundary pattern already used in console.ts and the file transport fix from #67953.

Proposed fix

In src/logging/subsystem.ts:

  • Import redactSensitiveText from ./redact.js.
  • In writeConsoleLine(), after Windows surrogate sanitization and before calling the sink, compute:
const redacted = redactSensitiveText(sanitized);
  • Pass redacted to sink.error, sink.warn, and sink.log.

This covers all subsystem console paths (trace/debug/info/warn/error/fatal and .raw()) because they share the same writeConsoleLine() exit.

Out of scope

Raw JSONL sinks (raw-stream, config-audit, cron run log, session transcript JSONL, etc.) are tracked separately under #64046 and are not part of this focused follow-up.

extent analysis

TL;DR

Apply the redactSensitiveText() function to the console output in writeConsoleLine() to prevent sensitive information leaks.

Guidance

  • Import redactSensitiveText from ./redact.js in src/logging/subsystem.ts to utilize the existing redaction functionality.
  • Modify writeConsoleLine() to compute the redacted output using const redacted = redactSensitiveText(sanitized); before passing it to the console sink.
  • Update the sink.error, sink.warn, and sink.log calls to use the redacted output instead of the original sanitized output.
  • Verify that the redaction is working correctly by testing with sensitive information in the log messages.

Example

import { redactSensitiveText } from './redact.js';

// ...

function writeConsoleLine(sanitized: string) {
  const redacted = redactSensitiveText(sanitized);
  // ...
  sink.log(redacted);
  // ...
}

Notes

This fix only addresses the console output of subsystem loggers and does not affect other logging paths, such as file logging or raw JSONL sinks, which are tracked separately under #64046.

Recommendation

Apply the proposed fix to prevent sensitive information leaks through console output. This change is necessary to ensure that sensitive information is properly redacted before being written to the console.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

Apply redactSensitiveText() at the writeConsoleLine() sink exit, matching the sink-boundary pattern already used in console.ts and the file transport fix from #67953.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING