惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

大猫的无限游戏
大猫的无限游戏
D
DataBreaches.Net
M
MIT News - Artificial intelligence
量子位
N
Netflix TechBlog - Medium
The Cloudflare Blog
The GitHub Blog
The GitHub Blog
P
Proofpoint News Feed
人人都是产品经理
人人都是产品经理
B
Blog RSS Feed
B
Blog
博客园_首页
博客园 - Franky
MyScale Blog
MyScale Blog
有赞技术团队
有赞技术团队
Apple Machine Learning Research
Apple Machine Learning Research
MongoDB | Blog
MongoDB | Blog
云风的 BLOG
云风的 BLOG
爱范儿
爱范儿
H
Help Net Security
Y
Y Combinator Blog
Stack Overflow Blog
Stack Overflow Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
酷 壳 – CoolShell
酷 壳 – CoolShell

Recent Commits to openclaw:main

test: merge chat side-result checks · openclaw/openclaw@ddd2c2a test: merge cron history checks · openclaw/openclaw@f7eb746 test: merge responsive navigation shell checks · openclaw/openclaw@c2e4b47 docs(changelog): add codex oauth fixes · openclaw/openclaw@628e6cd test: merge navigation routing cases · openclaw/openclaw@5d8cecb Tests: mock channel registry bundled fallback · openclaw/openclaw@2b08233 Secrets: avoid broad web search discovery for single plugin config · openclaw/openclaw@a464f59 test: merge config view browser checks · openclaw/openclaw@20cf511 fix(status): align oauth health with runtime · openclaw/openclaw@eed7116 feat: add macOS screen snapshots for monitor preview (#67954) thanks … · openclaw/openclaw@f377db1 fix: report shared auth scopes in hello-ok (#67810) thanks @BunsDev · openclaw/openclaw@0b6c39b Auto-reply: avoid eager bundled route fallback · openclaw/openclaw@3ea1bf4 Tests: narrow session binding contract setup · openclaw/openclaw@54e4e16 fix(macOS): enable undo/redo in webchat composer text input (#34962) · openclaw/openclaw@00951dc Tests: speed up channel setup promotion · openclaw/openclaw@82b529a Docs: refresh agent instructions · openclaw/openclaw@5775fe2 fix(auth): serialize OAuth refresh across agents to fix #26322 (#67876) · openclaw/openclaw@8e79080 test: allow ollama public surface boundary test · openclaw/openclaw@7d4f1a6 Docs: add test performance guardrails · openclaw/openclaw@89706d3 Tests: restore context-engine usage proof · openclaw/openclaw@e4c4f95 Tests: slim context engine runtime coverage · openclaw/openclaw@74c198f ci: retry failed custom checkouts · openclaw/openclaw@0ee5baf test: trim duplicate provider auth onboarding cases · openclaw/openclaw@1ffc02e matrix: fix sessions_spawn --thread subagent session spawning (#67643) · openclaw/openclaw@1ce2596 test: reduce auth choice fixture churn · openclaw/openclaw@857b9cd test: mock health status config boundaries · openclaw/openclaw@9d5ab4a test: mock onboard config io boundary · openclaw/openclaw@299694d test: mock legacy state plugin boundaries · openclaw/openclaw@2713089 test: mock channel install boundaries · openclaw/openclaw@b945248 test: mock doctor preview channel boundaries · openclaw/openclaw@b1a3ad4
fix(config-audit): redact CLI argv secrets before persist...
koshaji · 2026-05-01 · via Recent Commits to openclaw:main

@@ -7,6 +7,7 @@ import {

77

createConfigWriteAuditRecordBase,

88

finalizeConfigWriteAuditRecord,

99

formatConfigOverwriteLogMessage,

10+

redactConfigAuditArgv,

1011

resolveConfigAuditLogPath,

1112

} from "./io.audit.js";

1213

@@ -195,6 +196,231 @@ describe("config io audit helpers", () => {

195196

});

196197

});

197198199+

it("redacts argv values that follow known secret flag names", () => {

200+

const argv = [

201+

"node",

202+

"openclaw",

203+

"gateway",

204+

"--token",

205+

"super-secret-gateway-token-12345",

206+

"--api-key",

207+

"sk-very-real-looking-openai-api-key-AB12CD34",

208+

"--port",

209+

"8080",

210+

];

211+

const result = redactConfigAuditArgv(argv);

212+

expect(result).toEqual([

213+

"node",

214+

"openclaw",

215+

"gateway",

216+

"--token",

217+

"***",

218+

"--api-key",

219+

"***",

220+

"--port",

221+

"8080",

222+

]);

223+

});

224+225+

it("redacts the value half of `--flag=value` for secret flags", () => {

226+

const argv = ["openclaw", "--token=ghp_realgithubtoken1234567890ABCD", "--port=8080"];

227+

expect(redactConfigAuditArgv(argv)).toEqual(["openclaw", "--token=***", "--port=8080"]);

228+

});

229+230+

it("redacts standalone token shapes via the shared logging redaction patterns", () => {

231+

const argv = [

232+

"node",

233+

"openclaw",

234+

"ghp_realgithubtoken1234567890ABCD",

235+

"AIzaSyD-very-real-looking-google-api-key-123",

236+

"987654321:AAAAAAAAAAAAAAAAAAAAAAAAAAAA",

237+

];

238+

const result = redactConfigAuditArgv(argv);

239+

expect(result[0]).toBe("node");

240+

expect(result[1]).toBe("openclaw");

241+

for (const masked of result.slice(2)) {

242+

expect(masked).not.toContain("ghp_realgithubtoken");

243+

expect(masked).not.toContain("AIzaSyD-very-real-looking");

244+

expect(masked).not.toMatch(/AAAAAAAAAAAAAA/);

245+

}

246+

});

247+248+

it("leaves non-secret arguments untouched", () => {

249+

const argv = ["node", "openclaw", "gateway", "--port", "8080", "--bind", "lan"];

250+

expect(redactConfigAuditArgv(argv)).toEqual(argv);

251+

});

252+253+

it("redacts unknown but credential-suffixed flags via the heuristic classifier", () => {

254+

const argv = [

255+

"node",

256+

"openclaw",

257+

"--custom-api-key",

258+

"real-tenant-key-AB12CD34EF56GH78",

259+

"--alibaba-model-studio-api-key=plain-value-xyz-12345",

260+

"--app-token",

261+

"another-secret-value",

262+

"--frobnicate-credential=hidden",

263+

];

264+

const result = redactConfigAuditArgv(argv);

265+

expect(result).toEqual([

266+

"node",

267+

"openclaw",

268+

"--custom-api-key",

269+

"***",

270+

"--alibaba-model-studio-api-key=***",

271+

"--app-token",

272+

"***",

273+

"--frobnicate-credential=***",

274+

]);

275+

});

276+277+

it("redacts key-valued secret flags (Nostr --private-key, Matrix --recovery-key)", () => {

278+

const argv = [

279+

"node",

280+

"openclaw",

281+

"channels",

282+

"add",

283+

"--channel",

284+

"nostr",

285+

"--private-key",

286+

"nsec1realnostrprivatekeyvaluexyz1234567890",

287+

"--recovery-key=EsTb-ABCD-1234-EFGH-5678-IJKL-9012-MNOP",

288+

];

289+

const result = redactConfigAuditArgv(argv);

290+

expect(result).toEqual([

291+

"node",

292+

"openclaw",

293+

"channels",

294+

"add",

295+

"--channel",

296+

"nostr",

297+

"--private-key",

298+

"***",

299+

"--recovery-key=***",

300+

]);

301+

});

302+303+

it("redacts unknown *-key flags via the heuristic classifier (private/signing/master/etc.)", () => {

304+

const argv = [

305+

"node",

306+

"openclaw",

307+

"--my-plugin-private-key",

308+

"tenant-private-key-material-zzz",

309+

"--rotated-signing-key=PEM-LIKE-MATERIAL",

310+

"--ops-master-key",

311+

"ABCDEF1234567890",

312+

];

313+

const result = redactConfigAuditArgv(argv);

314+

expect(result).toEqual([

315+

"node",

316+

"openclaw",

317+

"--my-plugin-private-key",

318+

"***",

319+

"--rotated-signing-key=***",

320+

"--ops-master-key",

321+

"***",

322+

]);

323+

});

324+325+

it("masks the next arg after a secret flag even when it looks like another option", () => {

326+

const argv = ["openclaw", "--token", "--port", "8080"];

327+

expect(redactConfigAuditArgv(argv)).toEqual(["openclaw", "--token", "***", "8080"]);

328+

});

329+330+

it("redacts dash-leading secret values after bare secret flags", () => {

331+

const argv = ["openclaw", "--password", "-secret-value"];

332+

expect(redactConfigAuditArgv(argv)).toEqual(["openclaw", "--password", "***"]);

333+

});

334+335+

it("does not mask when a secret flag is the final arg with no value", () => {

336+

const argv = ["openclaw", "--token"];

337+

expect(redactConfigAuditArgv(argv)).toEqual(["openclaw", "--token"]);

338+

});

339+340+

it("caps caller-supplied processInfo argv at 8 entries before redaction", () => {

341+

const longArgv = [

342+

"node",

343+

"openclaw",

344+

"--api-key",

345+

"secret",

346+

"--port",

347+

"8080",

348+

"--bind",

349+

"lan",

350+

"--leaks-here-token",

351+

"this-must-not-land-in-audit-1234567890",

352+

];

353+

const base = createConfigWriteAuditRecordBase({

354+

configPath: "/tmp/openclaw.json",

355+

env: {} as NodeJS.ProcessEnv,

356+

existsBefore: true,

357+

previousHash: "prev",

358+

nextHash: "next",

359+

previousBytes: 1,

360+

nextBytes: 2,

361+

previousMetadata: {

362+

dev: null,

363+

ino: null,

364+

mode: null,

365+

nlink: null,

366+

uid: null,

367+

gid: null,

368+

},

369+

changedPathCount: 0,

370+

hasMetaBefore: true,

371+

hasMetaAfter: true,

372+

gatewayModeBefore: "local",

373+

gatewayModeAfter: "local",

374+

suspicious: [],

375+

now: "2026-04-30T00:00:00.000Z",

376+

processInfo: {

377+

pid: 1,

378+

ppid: 1,

379+

cwd: "/work",

380+

argv: longArgv,

381+

execArgv: [],

382+

},

383+

});

384+

expect(base.argv).toHaveLength(8);

385+

expect(base.argv).not.toContain("this-must-not-land-in-audit-1234567890");

386+

expect(base.argv).not.toContain("--leaks-here-token");

387+

});

388+389+

it("redacts processInfo.argv when explicitly supplied to createConfigWriteAuditRecordBase", () => {

390+

const base = createConfigWriteAuditRecordBase({

391+

configPath: "/tmp/openclaw.json",

392+

env: {} as NodeJS.ProcessEnv,

393+

existsBefore: true,

394+

previousHash: "prev",

395+

nextHash: "next",

396+

previousBytes: 1,

397+

nextBytes: 2,

398+

previousMetadata: {

399+

dev: null,

400+

ino: null,

401+

mode: null,

402+

nlink: null,

403+

uid: null,

404+

gid: null,

405+

},

406+

changedPathCount: 0,

407+

hasMetaBefore: true,

408+

hasMetaAfter: true,

409+

gatewayModeBefore: "local",

410+

gatewayModeAfter: "local",

411+

suspicious: [],

412+

now: "2026-04-30T00:00:00.000Z",

413+

processInfo: {

414+

pid: 1,

415+

ppid: 1,

416+

cwd: "/work",

417+

argv: ["node", "openclaw", "--token", "leaked-but-not-anymore-12345"],

418+

execArgv: [],

419+

},

420+

});

421+

expect(base.argv).toEqual(["node", "openclaw", "--token", "***"]);

422+

});

423+198424

it("also accepts flattened audit record params from legacy call sites", async () => {

199425

const home = await suiteRootTracker.make("append-flat");

200426

const record = createRenameAuditRecord(home);