SEC: canonical detector catches glued-prefix credentials at egress sinks - #1621
Draft
thesongzhu wants to merge 7 commits into
Draft
SEC: canonical detector catches glued-prefix credentials at egress sinks#1621thesongzhu wants to merge 7 commits into
thesongzhu wants to merge 7 commits into
Conversation
…redentials glued after a word char (leading \b evasion) across audit/realtime/memory egress sinks; bounded to high-entropy whole-match prefixes with a benign-identifier no-over-redaction corpus Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JhCDTLngxAf6MDh4Bfcd48
…ed a `_`-inclusive body that over-redacted benign snake_case ending in ghs/gho/ghp/ghr/ghu before `_` (walkthroughs_completed_counter → walkthrou[REDACTED_SECRET]); change the classic branch body to base62 (`[A-Za-z0-9]`, the real token shape) so a snake_case `_` breaks the body — glued real classic tokens still caught, benign identifiers unchanged; add ghs_ benign corpus to the detector + all 3 sinks Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JhCDTLngxAf6MDh4Bfcd48
…classic prefixes are common English WORD-FRAGMENTS (-ghs ends walkthroughs/coughs/highs; "github"), so a base62 body alone still over-redacted benign `<word>_<contiguous base62 run>` egress content (walkthroughs_completedThisWeek → walkthrou[REDACTED_SECRET]); the classic branch keeps \b (delimited/standalone/labeled tokens still caught, glued is an accepted documented gap like sk-/AIza/ya29./eyJ/xapp-); the other 10 de-\b'd prefixes are not word-fragments and stay de-\b'd; contiguous-run benign corpus added to detector + all 3 sinks Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JhCDTLngxAf6MDh4Bfcd48
…ation embeds English-word / base32-constructible fragments (ASIA/AIDA/AGPA) and its body is [0-9A-Z]{16} (the all-caps-constant / ULID alphabet), so de-\b over-redacted benign all-caps/ULID ids (012345AGPABCDEFGHJKMNPQRST → 012345[REDACTED_SECRET]; AUSTRALASIAWIDE… → AUSTRAL[REDACTED_SECRET]); the AKIA branch keeps \b (delimited/standalone/labeled AWS keys still caught, glued is an accepted documented gap like classic-github/sk-/AIza/ya29./xapp-); the other 9 de-\b'd prefixes (hf_/gsk_/npm_/dop_v1_/GOCSPX-/glpat-/SG./sq0/xox) empirically re-confirmed collision-free (non-word-fragment vendor prefixes, 0 diffs vs base on 9k natural-benign inputs); ULID/all-caps benign corpus added to detector + all 3 sinks
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JhCDTLngxAf6MDh4Bfcd48
…mily NO-DEGRADE fixtures — add narrow inline `pragma: allowlist secret` markers to each benign ULID/all-caps/base32/high-entropy test literal the scanner misclassifies (AWS Access Key / Base64 High Entropy false positives), and truncate/obfuscate the illustrative secret-shaped examples in the AKIA source comment; NO change to .secrets.baseline or the exclude-files glob (the scanner's own suggested mitigation). Local `detect-secrets-hook` now reports no new secrets; logic unchanged (pragmas are comments) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JhCDTLngxAf6MDh4Bfcd48
…x; de-`\b` only unambiguous members (ghp/ghr/AKIA) to catch glued credentials (SEC-SECRET-GLUED-PREFIX-001 P1)
The Advisor P1 audit found that keeping the leading `\b` on the WHOLE GitHub-classic
and AWS alternations left real credentials glued after a word char UNMATCHED
(`keyghp_<36>`, `keyAKIA<16>`) — they survived the detector, realtime redactor, memory
filter, and persisted audit JSONL. "Accepted gap" does not satisfy SEC-EVENT-REDACTION-001.
Fix: SPLIT each alternation into two patterns and drop the leading `\b` ONLY on the members
that are provably NOT a benign word / ULID / acronym fragment:
- GitHub classic {ghp,ghr} → de-`\b` (0 dict word-endings). {gho,ghs,ghu,github_pat_} keep `\b`
(word-endings sor-GHO / walkthrou-GHS / Ra-GHU; "github" is a word) — the mixed-case body
lets a lowercase snake_case identifier collide, so even obscure word-endings matter.
- AWS {AKIA} → de-`\b` (has `I` → not ULID-constructible; only obscure lowercase word-endings
that never form all-caps 20+ runs; no common all-caps acronym). {ASIA,AGPA,AIDA,AROA,AIPA,
ANPA,ANVA} keep `\b` (Eur-ASIA word / AGPA·ANPA·ANVA ULID-constructible / AIDA·AIPA→AIPAC
acronym / AOTE-AROA place) — the uppercase-only body only collides inside all-caps runs.
Glued `keyghp_`/`keyghr_`/`keyAKIA` are now redacted at the credential subspan (benign lead
preserved) at the detector, event-payload redactor, memory output filter, and audit-JSONL sink;
the benign no-degrade corpus (walkthroughs/coughs, ULIDs, ASIA/AIDA/AGPA all-caps, AIPAC/AOTEAROA
/CANVAS, sorgho_/raghu_) is byte-identical vs base. Bodies stay base62/`[0-9A-Z]{16}` and the
trailing `\b` is unchanged (open-ended `{16,}`, never tightened, so no real token slips it).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JhCDTLngxAf6MDh4Bfcd48
…hind — protect SLOVAKIA/CZECHOSLOVAKIA all-caps constants (SEC-SECRET-GLUED-PREFIX-001 round-5 NO-DEGRADE)
The Advisor found a NO-DEGRADE regression in the round-4 plain de-`\b` AKIA branch:
`AKIA` is the SUFFIX of the country names SLOVAKIA / CZECHOSLOVAKIA (proper nouns absent
from /usr/share/dict/words, so the per-word dict analysis missed them). A plain
leading-`\b` drop over-redacts an ALL-CAPS region constant —
`SLOVAKIAREGIONCODE2024AB` -> `SLOV[REDACTED_SECRET]` — at the detector, realtime
redactor, memory content/metadata, and audit JSONL.
Fix (AKIA branch only): change `/AKIA[0-9A-Z]{16}\b/gu` to a context-sensitive
negative-lookbehind `/(?<![A-Z0-9])AKIA[0-9A-Z]{16}\b/gu`. `AKIA` now matches only when
it starts a FRESH token (after a lowercase word char, symbol, whitespace, or string
start — the credential-glue case `keyAKIA<16>`), NOT when embedded after an UPPERCASE
letter or DIGIT (mid-all-caps-word `SLOVAKIA…`, mid-alphanumeric run `PROJECT2AKIA…`).
The lookbehind is zero-width, so the redacted span is still exactly `AKIA<16>` (benign
lead preserved). Robust — no per-word enumeration.
GitHub {ghp,ghr}, the AWS keep-`\b` branch, and the 9 vendor prefixes are UNCHANGED
(ghp/ghr are not substrings of any all-caps word; only AKIA is a country-word suffix).
RED on 2c83630 (`SLOVAKIAREGIONCODE2024AB` corrupted); GREEN after (unchanged through
detector + all 3 sinks). `keyAKIA<16>` + standalone/delimited AWS keys still caught at
all sinks; the whole prior benign corpus stays green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JhCDTLngxAf6MDh4Bfcd48
thesongzhu
marked this pull request as draft
July 19, 2026 22:52
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Defect (SEC-SECRET-GLUED-PREFIX-001 — P1 correction)
The canonical secret detector
findSecretShapeSpans/redactSecretShapesInString(
src/security/friday-secret-shape-redactor.ts) kept a leading\bon the WHOLEGitHub-classic and AWS alternations. That protected the benign word/base32 fragments
in those alternations — but it over-protected the SAFE members, so a real
GitHub-classic PAT and AWS access-key glued after a word char were left UNMATCHED:
keyghp_<36 base62>andkeyAKIA<16>(no boundary before the prefix) survivedverbatim through the detector → realtime redactor → memory output filter →
persisted audit JSONL.
An "accepted gap" for a real credential prefix does not satisfy
SEC-EVENT-REDACTION-001 (the canary must be ABSENT from every raw sink readback). The
prior PR body also mis-described these two families as already "de-
\b'd", whichthey were not — corrected below.
All egress sinks funnel through this single canonical detector — audit-read
(
friday-hub-audit-log-writer.ts), realtime on-wire(
friday-event-payload-redactor.ts), memory read-back(
friday-memory-output-filter.ts+friday-memory-pii-guard.ts), plus realtimepersistence/bus, legacy rewrite, WebSocket egress, execution-control audit, and
agent-run persistence — so detector + those 3 sinks + the audit-JSONL cross-sink parity
proof are representative of the whole egress surface.
Fix — split each alternation by prefix; catch a glued credential ONLY on the provably-unambiguous members
Each member of the GitHub-classic set
{gho,ghp,ghr,ghs,ghu}and the AWS set{AKIA,ASIA,AGPA,AIDA,AROA,AIPA,ANPA,ANVA}is classified with three criteria:(a) English word-ending (
grep /usr/share/dict/words) or a common proper-noun,(b) Crockford-base32 / ULID-constructible (ULID charset =
0-9 A-ZminusI,L,O,U;a member of only Crockford chars can sit mid-ULID), (c) a common all-caps acronym /
base32 fragment. A member catches a glued credential ONLY if it fails all three. The
GitHub body is MIXED-CASE base62 after
_, so a lowercase snake_case identifier cancollide → even obscure word-endings count. The AWS body is
[0-9A-Z]{16}UPPERCASE+digit,so a member only collides inside an all-caps / alphanumeric 20+ contiguous run.
Per-member classification
ghp\bghr\bghs\bgho\bghu\bgithub_pat_\bAKIAI)(?<![A-Z0-9])lookbehindASIAI)\bAGPA\bANPA\bANVA\bAIDAI)\bAROAO)\bAIPAI)\bAKIA — country-word suffix → context lookbehind (round-5 correction). The prior
round claimed AKIA had "no common all-caps word source"; that was wrong —
AKIAis thesuffix of SLOVAKIA and CZECHOSLOVAKIA (proper nouns absent from the dict, which
the per-word grep missed). A plain leading-
\bdrop over-redacts an all-caps regionconstant (
SLOVAKIAREGIONCODE…→SLOV[REDACTED]). So AKIA is de-bounded with acontext-sensitive negative-lookbehind
(?<![A-Z0-9]), NOT a plain\b-drop: itmatches only when
AKIAstarts a fresh token (after a lowercase word char / symbol /whitespace / string start — the credential-glue case), not when embedded after an
UPPERCASE letter or DIGIT (mid-all-caps-word
SLOVAKIA…, mid-alphanumericPROJECT2AKIA…).The lookbehind is zero-width, so the redacted span is still exactly
AKIA<16>.ghp/ghrneed no lookbehind — a repo-wide scan confirms neither is a substring of any all-caps word.
Resulting GitHub + AWS patterns
Bodies are unchanged (base62 /
[0-9A-Z]{16}); the open-ended{16,}is nevertightened to an exact length, so a longer real token cannot slip the trailing
\bandleak. The previously-shipped 9 de-
\b'd vendor prefixes (hf_,gsk_,npm_,dop_v1_,GOCSPX-,glpat-,SG.<22>.<43>,sq0atp-/sq0csp-, Slackxox[abprs]-),the AWS keep-
\bbranch, and the kept-\bshapes (sk-/rk-/ak-/xai-, Stripeunderscore, Slack
xapp-,AIza,ya29., JWTeyJ, Bearer / assignment) areUNCHANGED.
Red-first + NO-DEGRADE proof
7021926c(base): gluedkeyghp_<36>,keyghr_<…>,keyAKIA<16>returnverbatim, 0 spans at the detector and survive all sinks.
2c83630f(plain de-\bAKIA):SLOVAKIAREGIONCODE2024AB→SLOV[REDACTED_SECRET](and the free-text embedding) — the country-suffix over-redaction.key[REDACTED_SECRET]/aws[REDACTED_SECRET](credential subspan only, benign lead preserved) at the detector, event-payload
redactor (on-wire), memory output filter (content / metadata / tags legs), and the
audit-JSONL sink (cross-sink parity: memory egress == audit sink).
SLOVAKIA…/CZECHOSLOVAKIA…/PROJECT2AKIA…are unchanged through the detector and all 3 sinks.{gho,ghs,ghu}/{ASIA,AGPA,AIDA,AROA,AIPA, ANPA,ANVA}prefix standalone/delimited still redacts, but its glued form remainsan accepted gap (keeps
\b).(
walkthroughs_completedThisWeek,coughs_<hash>,breakthroughs_*), gho/ghu(
sorgho_yieldPerHectare2024xx,raghu_…), ULID/all-caps (012345AGPA…,AUSTRALASIA…,EURASIA…,PROJECTAIDA…), the (c) negative controls (AIPACPOLICYCONFERENCE…,AOTEAROANEWZEALAND…,OPENCANVAS…), the AKIA country-suffix controls(
SLOVAKIAREGIONCODE…,CZECHOSLOVAKIAREGIONCODE…), UUID/hex/base64url — all returnbyte-identical through the detector and the 3 sinks.
Gates
npx tsc --noEmit= 0 (V8 + tsconfig support the lookbehind +uflag);npm run lint= 0 errors.test/unit/securitytest/unit/memory/guard/services+test/unit/api/realtime— 60 files / 1167 testsgreen, no
.only/.skip.detect-secrets-hookv1.5.0 (exact CI command) → no new secrets (new PLACEHOLDER /AKIA-shaped fixture literals are
seg()-built and/or carry inlinepragma: allowlist secret)..secrets.baseline/ exclude-globchange.
Scope / honesty
Bounded to the leading-
\bover-protection on the GitHub-classic and AWS alternations,plus the AKIA country-suffix (SLOVAKIA/CZECHOSLOVAKIA) NO-DEGRADE follow-up. The prior
"GitHub classic and AWS are de-
\b'd", "ghp_ + AKIA glued is an accepted gap", and "AKIAhas no common all-caps word source" claims are all removed.
ghp/ghrare plain de-\b'd;AKIAis de-bounded via a context-sensitive(?<![A-Z0-9])lookbehind that preservesSLOVAKIA/CZECHOSLOVAKIA; the word/ULID/acronym members keep
\b.🤖 Generated with Claude Code
https://claude.ai/code/session_01JhCDTLngxAf6MDh4Bfcd48