Squashed 'scanners/commons/' changes from 4641a7b..7ce0ba7

7ce0ba7 docs(carriers): the third verdict exists, and publishing an alias is what takes it away
302625e fix(conformance): the tag carrier has no output: label, and our blocker claimed it did
fe5e6b2 docs(conventions): the merge button is off for a reason, and the reason now lives in the repo
2d86151 fix(divergence): our own iframe number read 3x low, and the reported cause was not the cause
daa7ba4 release(0.4.0): two values moved by two mechanisms, and the difference is the release
2eee7e1 feat(lexicon): both unbounded rows narrow to [^><]*, and the mechanism is new here
d467324 feat(signatures): the staleness we disclosed is closed by reading the module, not the message
4187715 docs(divergence): our own form has a number now, and it is quadratic
0e765a0 docs(security): the attack surface here is data, so the report route had to say where a wrong entry gets fixed
d96fbbf docs(divergence): the span row had one witness; llm-security measured five more

git-subtree-dir: scanners/commons
git-subtree-split: 7ce0ba706cadd032ec3c16622dcfdb5ce4dc32d6
This commit is contained in:
Kjell Tore Guttormsen 2026-08-13 20:08:20 +02:00
commit bc23b07cf9
8 changed files with 844 additions and 41 deletions

View file

@ -1,10 +1,10 @@
{
"version": "0.1.0",
"version": "0.3.0",
"id": "secret-egress",
"description": "Credential and token shapes that must never leave a machine: the fixed pattern table a pre-write guard matches against content before it is persisted. Detection data only - what to DO when one matches (block, warn, redact) is the consumer's policy and is not described here.",
"owasp": "LLM02",
"match_semantics": "first match wins; patterns are evaluated in ascending `order`",
"$comment": "Extracted without behaviour change from llm-security/hooks/scripts/pre-edit-secrets.mjs (`SECRET_PATTERNS`), delivered as operator dump 2/2 through the local coord mailbox on 2026-08-09. NOTE THE SOURCE FILE: the dump states explicitly that this is the engine-consumed hook table and NOT knowledge/secrets-patterns.md, which is a separate PCRE-flavoured agent-consumed variant that stays where it is. This repository's own extraction plan originally named the wrong one of the two; the file recorded here is the one that was actually delivered. Only the 18 fixed entries are data - the dump states that entries 19 and beyond are policy-injected custom patterns at runtime and are not part of the base table.",
"$comment": "Extracted without behaviour change from llm-security/hooks/scripts/pre-edit-secrets.mjs (`SECRET_PATTERNS`). NOTE THE SOURCE FILE: this is the engine-consumed hook table and NOT knowledge/secrets-patterns.md, which is a separate PCRE-flavoured agent-consumed variant that stays where it is. This repository's own extraction plan originally named the wrong one of the two; the file recorded here is the one that was actually delivered. Only the 19 fixed entries are data - entries 20 and beyond are policy-injected custom patterns at runtime and are not part of the base table. Version 0.3.0 re-extracted the table from a pinned public commit rather than from a transcription: positions 0-16 were confirmed byte-identical to what the 0.1.0 dump had already produced, and order 17 (`OpenAI Legacy API Key`) was read out of the module at that commit. The one-entry staleness disclosed in 0.2.0 is therefore closed by measurement, not by transcribing the regex out of the coord message that reported it.",
"provenance": {
"source_repo": "llm-security",
"source_files": [
@ -13,13 +13,15 @@
"source_exports": [
"SECRET_PATTERNS"
],
"source_delivery": "operator dump 2/2, coord message from llm-security, 2026-08-09",
"source_commit": "unknown - not supplied with the dump",
"verified": "differentially, against the dump",
"source_delivery": "0.1.0: operator dump 2/2, coord message from llm-security, 2026-08-09. 0.3.0: re-extracted from the module text at a pinned public commit, obtained with `git show <commit>:hooks/scripts/pre-edit-secrets.mjs` against the public remote.",
"source_commit": "47905dacae8bd5613c8ed76c088cb3de93f40091",
"source_commit_note": "`refs/heads/main` on the public remote when 0.3.0 was extracted. The commit that introduced order 17 is `088e458`, confirmed here to be an ancestor of the pinned head with `git merge-base --is-ancestor`, rather than accepted from the reporting message.",
"verified": "positionally against the module at the pinned commit: name, regex source, flags and order compared for all 19 entries, 0 divergences",
"evidence_limits": [
"The dump is a transcription of the source module, not the module file itself. The checks recorded for this file prove that this JSON agrees with the DUMP; dump-to-module fidelity is llm-security's assertion, not a result reproduced here.",
"No severity, and no per-entry disposition, was supplied. The source table carries a name and a pattern and nothing else, so neither is invented here.",
"The runtime-injected custom patterns (entries 19+) are policy, not data, and are out of scope. A consumer that matches only this table matches LESS than the seed hook does when a policy is loaded."
"The runtime-injected custom patterns (entries 20+) are policy, not data, and are out of scope. A consumer that matches only this table matches LESS than the seed hook does when a policy is loaded.",
"Fidelity is asserted against ONE commit. The pinned commit above is where this table was read; it says nothing about any later state of the source module. A consumer that needs to know whether it has drifted must re-measure against the remote, not re-read this field.",
"The comparison covers what the table declares - name, pattern source, flags, order. It does not cover the surrounding module: how the guard reads content, what it does on a match, or which paths it exempts are engine behaviour and are deliberately absent from this file."
]
},
"ordering": {
@ -29,7 +31,7 @@
},
"dialect": {
"name": "ecmascript",
"$comment": "Patterns are ECMAScript regular-expression source text exactly as the source literals spell it. Flags are declared per pattern; an entry with no `flags` key carries no flags. All 18 compile in Node with their declared flags, in Node with `u` added, and in Python `re` with the equivalent re.I.",
"$comment": "Patterns are ECMAScript regular-expression source text exactly as the source literals spell it. Flags are declared per pattern; an entry with no `flags` key carries no flags. All 19 compile in Node with their declared flags, in Node with `u` added, and in Python `re` with the equivalent re.I.",
"flags": {
"i": "case-insensitive"
},
@ -40,13 +42,13 @@
"character classes"
],
"translation_notes": [
"Python (`re`): compile with re.I where flags contain `i`. No rewriting needed; verified by compiling all 18.",
"Python (`re`): compile with re.I where flags contain `i`. No rewriting needed; verified by compiling all 19.",
"Two patterns contain `\\/` - the redundant escape a JavaScript regex LITERAL requires and that `RegExp.prototype.source` preserves ('Slack/Discord Webhook URL' and 'Database connection string'). Kept byte-identical because Node bare, Node under `u` and Python `re` all accept it. Engines that reject unknown escapes (Go `regexp`, RE2) MUST report these two as unsupported rather than skip them silently.",
"The 'Generic credential assignment' and 'Authorization header with token' entries are shape matches, not proofs of a live credential. A consumer treating every match as a confirmed leak will produce false positives; that trade-off belongs to the consumer's policy, not to this table."
]
},
"normalisations": [],
"normalisations_note": "Empty by result, not by omission: all 18 patterns are byte-identical to the source, verified below. No escaping change was needed.",
"normalisations_note": "Empty by result, not by omission: all 19 patterns are byte-identical to the source module at the pinned commit, compared positionally. No escaping change was needed.",
"patterns": [
{
"order": 0,
@ -141,9 +143,14 @@
},
{
"order": 17,
"name": "OpenAI Legacy API Key",
"pattern": "\\bsk-[A-Za-z0-9]{20}T3BlbkFJ[A-Za-z0-9]{20}\\b"
},
{
"order": 18,
"name": "JWT (three-part token)",
"pattern": "\\beyJ[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}\\.[A-Za-z0-9_-]{10,}\\b"
}
],
"count": 18
"count": 19
}