Skip to content

Commit b657261

Browse files
committed
Deny editor tilde and swap backups of credential files
1 parent 6f1000d commit b657261

2 files changed

Lines changed: 35 additions & 1 deletion

File tree

‎src/auth/credential-surface.ts‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,11 @@ export function buildCredentialPatterns(): RegExp[] {
5858
const base = escapeRegExp(basename);
5959
// Editor backup copies keep full credential bytes next to the live file.
6060
// Scoped to the settings dir and anchored to known basenames, never a
61-
// generic *.bak.
61+
// generic *.bak, *~, or *.swp.
6262
patterns.push(new RegExp(`(^|\\/)${dir}\\/${base}\\.bak[^/]*$`));
63+
patterns.push(new RegExp(`(^|\\/)${dir}\\/${base}~$`));
64+
patterns.push(new RegExp(`(^|\\/)${dir}\\/${base}\\.swp$`));
65+
patterns.push(new RegExp(`(^|\\/)${dir}\\/\\.${base}\\.swp$`));
6366
patterns.push(new RegExp(`(^|\\/)${base}\\.lock$`));
6467
// Writers emit a pid.counter middle segment (auth/store.ts,
6568
// mcp/auth-store.ts), so the middle segment is required; a bare

‎src/plugins/secret-guard-credential-surface.test.ts‎

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,22 @@ describe("CL-7789 default-install credential surface", () => {
132132
expect(
133133
isSensitivePathResolved(join(home, ".corbits", "codex-auth.json.lock")),
134134
).toBe(true);
135+
for (const basename of [
136+
"settings.json",
137+
"permissions.json",
138+
"codex-auth.json",
139+
"xai-auth.json",
140+
]) {
141+
expect(
142+
isSensitivePathResolved(join(home, ".corbits", `${basename}~`)),
143+
).toBe(true);
144+
expect(
145+
isSensitivePathResolved(join(home, ".corbits", `${basename}.swp`)),
146+
).toBe(true);
147+
expect(
148+
isSensitivePathResolved(join(home, ".corbits", `.${basename}.swp`)),
149+
).toBe(true);
150+
}
135151
expect(
136152
isSensitivePathResolved(
137153
join(home, ".corbits", "xai-auth.json.12345.1.tmp"),
@@ -157,6 +173,21 @@ describe("CL-7789 default-install credential surface", () => {
157173
}
158174
});
159175

176+
test("@mentions of credential backup paths stay blocked without leaking bytes", async () => {
177+
const fake = await fakeHome();
178+
const cwd = await mkdtemp(join(tmpdir(), "cl7789-mention-bak-cwd-"));
179+
try {
180+
const backup = `${fake.codexAuth}.bak-2026-01-01`;
181+
await writeFile(backup, `${CODEX_BYTES}\n`);
182+
const resolved = await resolveAtMentions(`read @${backup}`, cwd);
183+
expect(resolved).toContain("(blocked: sensitive path)");
184+
expect(resolved).not.toContain("CODEX-FIXTURE-ACCESS");
185+
} finally {
186+
await fake.cleanup();
187+
await rm(cwd, { recursive: true, force: true });
188+
}
189+
});
190+
160191
test("a symlink to a credential file is blocked by mention and by read", async () => {
161192
const fake = await fakeHome();
162193
const cwd = await mkdtemp(join(tmpdir(), "cl7789-symlink-cwd-"));

0 commit comments

Comments
 (0)