From f19fc26f00eddf7629c20d89f62e01066ae7a672 Mon Sep 17 00:00:00 2001 From: jaso0n0818 Date: Mon, 29 Jun 2026 15:18:24 +0000 Subject: [PATCH] fix(signals): redact /var/ paths in the manifest public-safe guard MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit isFocusManifestPublicSafe (the public-output safety gate for contributor-issue drafts and decision packs) lists local-filesystem path prefixes that must mirror the canonical PUBLIC_UNSAFE_PATTERN in redaction.ts, which redacts /Users/, /home/, /root/, /var/, and /tmp/. This guard still omits /var/, so a manifest string containing a /var/ path — /var/log/..., /var/folders/..., or a CI workspace under /var/ — passes as public-safe and leaks a local filesystem path into public output. Add /var/ to the path alternatives so the guard matches the canonical set exactly. Extends the existing path regression test with a /var/ case. No linked issue: a one-line, self-evident security fix that completes the canonical path parity, no behavior change beyond closing the leak, no API/schema/DB change. --- src/signals/focus-manifest.ts | 9 +++++---- test/unit/focus-manifest.test.ts | 1 + 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/signals/focus-manifest.ts b/src/signals/focus-manifest.ts index 1638f365f4..a3a97b264e 100644 --- a/src/signals/focus-manifest.ts +++ b/src/signals/focus-manifest.ts @@ -289,10 +289,11 @@ const EMPTY_MANIFEST: FocusManifest = { * text must not leak reward, wallet/key, ranking, or local filesystem path material. */ export function isFocusManifestPublicSafe(text: string): boolean { - // Local filesystem path alternatives mirror the canonical PUBLIC_UNSAFE_PATTERN in redaction.ts: include - // `/root/` (container/CI home) and accept the forward-slash Windows form (`C:/Users/`), not only the - // backslash one — otherwise a `/root/...` or `C:/Users/...` path leaks through this public-safe guard. - return !/\b(reward\w*|score\w*|wallets?|hotkeys?|coldkeys?|seed[-\s]?phrases?|mnemonics?|private[-\s]?keys?|farming|payouts?|rankings?|raw[-\s]?trust(?:[-\s]?scores?)?|trust[-\s]?scores?|private[-\s]?reviewability|reviewability(?:[-\s]?internals?)?|private[-\s]?scoreability|scoreability|public[-\s]?score[-\s]?(?:estimate|prediction|claim)s?|estimated[-\s]?scores?|score[-\s]?(?:estimate|prediction|preview)s?)\b|\/Users\/|\/home\/|\/root\/|\/tmp\/|[A-Z]:[\\/]Users[\\/]/i.test(text); + // Local filesystem path alternatives mirror the canonical PUBLIC_UNSAFE_PATTERN in redaction.ts: the full + // set is `/Users/`, `/home/`, `/root/` (container/CI home), `/var/` (logs, temp, CI workspaces), `/tmp/`, + // and the Windows `[A-Z]:[\/]Users[\/]` form (both slash directions). Any omission leaks that path prefix + // through this public-safe guard. + return !/\b(reward\w*|score\w*|wallets?|hotkeys?|coldkeys?|seed[-\s]?phrases?|mnemonics?|private[-\s]?keys?|farming|payouts?|rankings?|raw[-\s]?trust(?:[-\s]?scores?)?|trust[-\s]?scores?|private[-\s]?reviewability|reviewability(?:[-\s]?internals?)?|private[-\s]?scoreability|scoreability|public[-\s]?score[-\s]?(?:estimate|prediction|claim)s?|estimated[-\s]?scores?|score[-\s]?(?:estimate|prediction|preview)s?)\b|\/Users\/|\/home\/|\/root\/|\/var\/|\/tmp\/|[A-Z]:[\\/]Users[\\/]/i.test(text); } function emptyManifest(source: FocusManifestSource, warnings: string[] = []): FocusManifest { diff --git a/test/unit/focus-manifest.test.ts b/test/unit/focus-manifest.test.ts index f13c37225a..add859dac6 100644 --- a/test/unit/focus-manifest.test.ts +++ b/test/unit/focus-manifest.test.ts @@ -718,6 +718,7 @@ describe("public-safe invariant", () => { expect(isFocusManifestPublicSafe("see /Users/me/repo/src")).toBe(false); expect(isFocusManifestPublicSafe("see /home/dev/repo/src")).toBe(false); expect(isFocusManifestPublicSafe("see /root/repo/src")).toBe(false); + expect(isFocusManifestPublicSafe("see /var/log/build.log")).toBe(false); expect(isFocusManifestPublicSafe("see /tmp/build/out")).toBe(false); // Windows, both backslash and forward-slash forms. expect(isFocusManifestPublicSafe("see C:\\Users\\me\\repo")).toBe(false);