Development record
The canonical scanner's ScanText does not find a secret token glued behind a letter, a digit or an underscore, so the launch scan, the memory writer's page-name bar (judgeFilename) and every store-before-commit redactor share the blind spot. Every bundled secret pattern opens on a leading word boundary and a word character before the token removes it: judgeFilename accepts topic_auth_x followed by a GitHub PAT and y, .md, because no underscore suffix of filenameJudgeTexts starts at the token, and the history, memory and capture redactors leave the same spelling raw in what they store. scanAllPatterns' adjacency probes recover a token that abuts a token already found, never one that abuts ordinary text; its own comment names the limitation as accepted. Found by the security review of lane drainEcho3 (INFO), beside iss-2609290541525428. Measured before deciding: the glued sweep that closes the refusal gap, run over all 4605 tracked text files of the repository, adds 0 findings to ScanText's 13 hard_fail secret findings, the launch dry-run's finding count stays 1, and the sweep costs 7 to 10 per cent of the bounded scan's time. Fix direction: run the glued sweep inside scanText, so every consumer inherits it. Detector: ScanText reports a token glued behind a letter, a digit or an underscore at its own byte span, and the memory writer refuses a page whose slug carries one.
The canonical scanner's ScanText does not find a secret token glued behind a letter, a digit or an underscore, so the launch scan, the memory writer's page-name bar (judgeFilename) and every store-before-commit redactor share the blind spot. Every bundled secret pattern opens on a leading word boundary and a word character before the token removes it: judgeFilename accepts topic_auth_x followed by a GitHub PAT and y, .md, because no underscore suffix of filenameJudgeTexts starts at the token, and the history, memory and capture redactors leave the same spelling raw in what they store. scanAllPatterns' adjacency probes recover a token that abuts a token already found, never one that abuts ordinary text; its own comment names the limitation as accepted. Found by the security review of lane drainEcho3 (INFO), beside iss-2609290541525428. Measured before deciding: the glued sweep that closes the refusal gap, run over all 4605 tracked text files of the repository, adds 0 findings to ScanText's 13 hard_fail secret findings, the launch dry-run's finding count stays 1, and the sweep costs 7 to 10 per cent of the bounded scan's time. Fix direction: run the glued sweep inside scanText, so every consumer inherits it. Detector: ScanText reports a token glued behind a letter, a digit or an underscore at its own byte span, and the memory writer refuses a page whose slug carries one.
Grounds
- pursued: ScanText reports a glued token at its span, the memory writer refuses a page whose slug carries one, and the repository's own tree gains no finding; a glued token passing the scan, a false positive on ordinary snake_case text, or a linear-cost guard failing would show it wrong
Frontmatter
| id | iss-2609290551363398 |
|---|---|
| type | issue |
| lifecycle | resolved |
| severity | minor |
.abcd/work/issues/resolved/iss-2609290551363398-scantext-does-not-find-a-token-glued.md
open on GitHub ↗ · commit history ↗
mentions1
- iss-2609290541525428scanner.RedactRefusal does not seal a token glued behind a word character. The scanner's bundled secret patterns anchor their start on a leading word boundary, and '_' and every letter or digit are word characters, so a token that sits right after one has no boundary and is never matched: the implement loop's laneFileGap (internal/core/implement/loop/receipt.go) returns the receipt's path as notes_ followed by a GitHub PAT and .md, does not exist, with the token raw, and memory's ValidateDistilledPage (internal/core/memory/schema.go) returns unknown key(s) [notes_ followed by the token] raw, while notes- and sub/ spellings seal. A letter on both sides (x, token, y) is missed the same way. Every RedactRefusal caller shares the gap (scribe, release, ideate, lifeboat, reading, intent, memory, implement loop), so a host payload's key or path carries a credential to the terminal and the transcript through a refusal. It is the refusal-side twin of the page-filename gap iss-2609290411321963 closed with filenameJudgeTexts. Found by the security review of lane drainEcho3. Fix direction: in the primitive, not the callers; re-find the secret patterns with their leading boundary removed, through the scanner's own linear adjacency machinery, and seal every glued match byte for byte through Redact; fail closed as before. Detector: a refusal naming a key or a path in which a well-formed token sits behind an underscore or a letter carries the token sealed.