diff --git a/src/config/io.audit.test.ts b/src/config/io.audit.test.ts index 7de6fc89322..db3614d6f27 100644 --- a/src/config/io.audit.test.ts +++ b/src/config/io.audit.test.ts @@ -322,9 +322,14 @@ describe("config io audit helpers", () => { ]); }); - it("does not mask the next arg when a secret flag is followed by another option", () => { + it("masks the next arg after a secret flag even when it looks like another option", () => { const argv = ["openclaw", "--token", "--port", "8080"]; - expect(redactConfigAuditArgv(argv)).toEqual(["openclaw", "--token", "--port", "8080"]); + expect(redactConfigAuditArgv(argv)).toEqual(["openclaw", "--token", "***", "8080"]); + }); + + it("redacts dash-leading secret values after bare secret flags", () => { + const argv = ["openclaw", "--password", "-secret-value"]; + expect(redactConfigAuditArgv(argv)).toEqual(["openclaw", "--password", "***"]); }); it("does not mask when a secret flag is the final arg with no value", () => { diff --git a/src/config/io.audit.ts b/src/config/io.audit.ts index 808712017b3..4066640acfd 100644 --- a/src/config/io.audit.ts +++ b/src/config/io.audit.ts @@ -76,9 +76,9 @@ function parseFlagName(arg: string): string | null { // 1. `--flag=value` form for any name matching the explicit list or the // suffix heuristic — mask the value half. // 2. value following a bare `--flag` form — emit `***` instead of the -// next arg, but only when the candidate value does not itself look -// like another option (`-`/`--` prefix). A bare `--token --port 8080` -// is treated as a missing value, leaving `--port` and `8080` intact. +// next arg, even if it starts with `-`. Command parsers accept +// dash-leading values for required options, and this persistent audit +// log should fail closed. // 3. fall back to redactToolPayloadText for everything else, which catches // `KEY=VALUE` env-style assignments, raw token shapes (sk-, ghp_, xox*, // gsk_, AIza*, npm_, Telegram bot tokens, PEM blocks, Bearer headers, @@ -95,13 +95,8 @@ export function redactConfigAuditArgv(argv: readonly string[]): string[] { } if (redactNext) { redactNext = false; - if (!current.startsWith("-")) { - result.push("***"); - continue; - } - // The previous arg looked like a secret flag but was followed by - // another option — treat as a missing value and fall through so the - // current arg is processed normally. + result.push("***"); + continue; } const currentFlag = parseFlagName(current); if (currentFlag !== null && isSecretFlagName(currentFlag)) {