From 48352534a24ce0a3b0c5153e14c5fe2b4235a1fd Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 28 Mar 2026 10:10:49 -0700 Subject: [PATCH] Restrict result file permissions and redact agent output - Write .thinktank/ files with mode 0o600 (owner read/write only) - Redact agent stdout/stderr from saved JSON results to prevent credential exposure from build output or Claude debug logs - Worktrees still available for full output inspection Closes #24 Co-Authored-By: Claude Opus 4.6 (1M context) --- src/commands/run.ts | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/commands/run.ts b/src/commands/run.ts index 5f007c8..bc08163 100644 --- a/src/commands/run.ts +++ b/src/commands/run.ts @@ -92,12 +92,24 @@ async function saveResult(result: EnsembleResult): Promise { const dir = ".thinktank"; await mkdir(dir, { recursive: true }); - // Save full result + // Strip agent stdout/stderr from saved results to avoid credential exposure + const sanitizedResult = { + ...result, + agents: result.agents.map((a) => ({ + ...a, + output: a.output ? "[redacted — use worktree to inspect]" : "", + error: a.error ? "[redacted]" : undefined, + })), + }; + + // Save full result with restricted permissions (owner read/write only) const filename = `run-${result.timestamp.replace(/[:.]/g, "-")}.json`; - await writeFile(join(dir, filename), JSON.stringify(result, null, 2)); + await writeFile(join(dir, filename), JSON.stringify(sanitizedResult, null, 2), { mode: 0o600 }); // Save as latest - await writeFile(join(dir, "latest.json"), JSON.stringify(result, null, 2)); + await writeFile(join(dir, "latest.json"), JSON.stringify(sanitizedResult, null, 2), { + mode: 0o600, + }); console.log(` Results saved to ${join(dir, filename)}`); console.log();