fix(config-audit): fail closed for secret argv values

This commit is contained in:
Sally O'Malley
2026-04-30 21:12:02 -04:00
committed by sallyom
parent 2f9f883e46
commit 3dc54de1a8
2 changed files with 12 additions and 12 deletions

View File

@@ -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", () => {

View File

@@ -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)) {