Credential leak guard must require a word boundary or it blocks a filename containing "sk-
hermes-cron · confidence high · status active
tags: knowledgelayer sync guard regex false-positive
Observed 2026-09-21 05:45 AEST on Zappo (macbook-pro-3). The daily knowledgelayer-sync-daily
job failed with kl sync: BLOCKED — credential-shaped string tracked in repo; scrub before push.
Cause: the leak guard regex matched sk- anywhere in the text. The lesson filename
lessons/2026-09-11-disk-full-broke-cron-ledger-monitor-watched-sealed-volume.md contains the
substring isk-full... (from disk-full), which satisfies sk-[A-Za-z0-9]{20,} because isk-full
plus the rest of the filename runs past 20 characters. No credential was present. The guard looked
only at tracked *.md content, so one referenced path poisoned the whole sync.
The fix in both guard locations (~/.hermes/bin/kl sync step, tools/kl.py LEAK) adds a
non-key-character boundary: bash ERE uses (^|[^A-Za-z0-9_-]), Python uses (?<![A-Za-z0-9_-]).
Both keep the remaining alternatives unchanged.
Rule: a substring-based secret scanner must anchor on a boundary. Without one, ordinary prose
(disk-full, task-force, risk-mitigation) trips it and the guard stops the pipeline it is
meant to protect.
Verification after the fix: unit cases pass (sk-proj-..., legacy sk-, ghp_, AKIA, PEM header,
JWT each match; the lesson filename does not). A staged probe file containing a real sk-proj- key
was still blocked. kl sync then ran clean and pushed 5b6ed14; local and origin/main matched at
0 ahead / 0 behind.
Note: the stale second clone at ~/Projects/knowledgelayer (HEAD 5fb5499) still holds the unfixed
kl.py. It is not on the sync path; fix or remove it if it is ever revived.
2026-10-04 recurrence: the same bug in the publish guard
The fix above was applied to the two sync guards and never to the publish guard, so the same false positive blocked the website publish for another two weeks.
Observed 2026-10-04 21:26 AEST, a manual run of publish-site.sh on Zappo. It failed with
Error: Leak guard: credential-shaped string in lessons/2026-09-20-weekly-disk-hygiene-...md (/sk-[A-Za-z0-9_-]\{20,}/). The match was once again a filename slice: the referenced lesson
path contains disk-full, and its isk-full... run satisfies the pattern for 55 characters.
Four locations in the canonical tree tripped it: two index.json path entries and two prose
references to the same lesson.
Cause of the recurrence: the pattern lived in ai-hub/scripts/sync-knowledgelayer.mjs
(LEAK_PATTERNS, line 35), a separate implementation from tools/kl.py, so fixing the Python
guard did nothing for the publish path. A shared bug needs a fix in every implementation, not the
first one found.
Fix 2026-10-04: LEAK_PATTERNS entries are now built with a leading
(?<![A-Za-z0-9_-]) boundary, matching the Python guard. AKIA additionally requires
(?<![0-9A-Z]) because its character class overlaps its own prefix, so a bare lookbehind would
never match it. Verified: node --check passes, the real index.json no longer trips the guard,
sk-proj-..., ghp_..., AKIA... and AIza... still match, a dry sync-knowledgelayer.mjs run
exits 0 over 107 files, and the repo's 29 node tests pass.
Caveat found while writing this note: a boundary-anchored pattern still false-positives when the
prose wraps a filename across a line break, because the newline supplies the boundary the guard
wants. This note tripped kl.py's guard for exactly that reason before the wording changed.
Keep a long path on one line, or describe the matching substring instead of quoting the path.
Rule: when a leak-guard or scan pattern exists in more than one implementation, fix every copy and record where each one lives. A single-implementation fix leaves the others blocking silently.
Sources:
~/.hermes/bin/kl · ~/.hermes/knowledgelayer/tools/kl.py · kl sync run 2026-09-21 05:45 AEST