diff --git a/CHANGELOG.md b/CHANGELOG.md index fd1da947ac3..bcec7b1e6de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ Docs: https://docs.openclaw.ai ### Fixes +- Security/CLI: redact sensitive values in `openclaw config get` output before printing config paths, preventing credential leakage to terminal output/history. (#13683) Thanks @SleuthCo. - Install/Discord Voice: make `@discordjs/opus` an optional dependency so `openclaw` install/update no longer hard-fails when native Opus builds fail, while keeping `opusscript` as the runtime fallback decoder for Discord voice flows. (#23737, #23733, #23703) Thanks @jeadland, @Sheetaa, and @Breakyman. - Docker/Setup: precreate `$OPENCLAW_CONFIG_DIR/identity` during `docker-setup.sh` so CLI commands that need device identity (for example `devices list`) avoid `EACCES ... /home/node/.openclaw/identity` failures on restrictive bind mounts. (#23948) Thanks @ackson-beep. - Exec/Background: stop applying the default exec timeout to background sessions (`background: true` or explicit `yieldMs`) when no explicit timeout is set, so long-running background jobs are no longer terminated at the default timeout boundary. (#23303) diff --git a/src/cli/config-cli.test.ts b/src/cli/config-cli.test.ts index 5ae2e1edc81..392be2ad0cc 100644 --- a/src/cli/config-cli.test.ts +++ b/src/cli/config-cli.test.ts @@ -143,6 +143,23 @@ describe("config cli", () => { }); }); + describe("config get", () => { + it("redacts sensitive values", async () => { + const resolved: OpenClawConfig = { + gateway: { + auth: { + token: "super-secret-token", + }, + }, + }; + setSnapshot(resolved, resolved); + + await runConfigCommand(["config", "get", "gateway.auth.token"]); + + expect(mockLog).toHaveBeenCalledWith("__OPENCLAW_REDACTED__"); + }); + }); + describe("config set parsing flags", () => { it("falls back to raw string when parsing fails and strict mode is off", async () => { const resolved: OpenClawConfig = { gateway: { port: 18789 } }; diff --git a/src/cli/config-cli.ts b/src/cli/config-cli.ts index 1a6a9e11d3e..c9fb6e33520 100644 --- a/src/cli/config-cli.ts +++ b/src/cli/config-cli.ts @@ -1,6 +1,7 @@ import type { Command } from "commander"; import JSON5 from "json5"; import { readConfigFileSnapshot, writeConfigFile } from "../config/config.js"; +import { redactConfigObject } from "../config/redact-snapshot.js"; import { danger, info } from "../globals.js"; import type { RuntimeEnv } from "../runtime.js"; import { defaultRuntime } from "../runtime.js"; @@ -232,7 +233,8 @@ export async function runConfigGet(opts: { path: string; json?: boolean; runtime try { const parsedPath = parseRequiredPath(opts.path); const snapshot = await loadValidConfig(runtime); - const res = getAtPath(snapshot.config, parsedPath); + const redacted = redactConfigObject(snapshot.config); + const res = getAtPath(redacted, parsedPath); if (!res.found) { runtime.error(danger(`Config path not found: ${opts.path}`)); runtime.exit(1);