release(0.4.0): two values moved by two mechanisms, and the difference is the release
One table re-extracted from a pinned upstream commit, the way every value here has moved until now. Two lexicon rows authored here at the source owner's direction, which has never happened before and needed a reason that is not "we measured it and we were right." Consumers: byte-identity against v0.3.0 goes red by construction - pattern text changed. Ids, labels, aliases, family membership, case ids and every count are unchanged. README version sync: vendoring examples move to v0.4.0 (both subtree and fork-and-own), the secret-egress table count 18 -> 19, and the divergence-doc row stops claiming no data file was changed because of it. Two were - and the row now says why that did not come from the document. Verified: JSON well-formed, every JSON has top-level version, every spec still normative, charter clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JLEZ4XCSnSrQUFA8SzkQB4
This commit is contained in:
parent
2eee7e19ee
commit
daa7ba4c1c
2 changed files with 81 additions and 16 deletions
85
CHANGELOG.md
85
CHANGELOG.md
|
|
@ -9,26 +9,91 @@ Versioning note: the repository tag versions **the contract** (file set, key nam
|
|||
case ids, disposition semantics). Each JSON file additionally carries its own
|
||||
`"version"` field, bumped when that file changes.
|
||||
|
||||
## [Unreleased]
|
||||
## [0.4.0] — 2026-08-11
|
||||
|
||||
**Two detection values changed, by two different mechanisms, and the difference between those
|
||||
mechanisms is the point of the release.** One pattern table was **re-extracted** from a pinned
|
||||
upstream commit, the way every value in this repository has moved until now. Two lexicon rows were
|
||||
**authored here at the source owner's direction**, which has never happened before and required a
|
||||
reason that is not "we measured it and we were right."
|
||||
|
||||
A runtime that vendors this repository will see findings change. Any consumer asserting
|
||||
byte-identity against `v0.3.0` goes red by construction — `lexicon/injection-lexicon.json` changed
|
||||
pattern text. Ids, labels, aliases, family membership, case ids and every count are unchanged.
|
||||
|
||||
### Changed
|
||||
|
||||
- `lexicon/injection-lexicon.json` `0.7.0` → `0.8.0` — **`hybrid-xss:script-tag` and
|
||||
`hybrid-xss:iframe-src` narrow their unbounded negated class from `[^>]*` to `[^><]*`.** Both
|
||||
forms are quadratic in scan length on input that repeats the tag prefix and never supplies a
|
||||
`>`: each occurrence is a match start and `[^>]*` scans to end of input from each one. Measured
|
||||
in Node v25.8.2 at 16k / 32k / 64k / 128k / 256k chars — script-tag 32.65 / 113.36 / 479.02 /
|
||||
1988.83 / **7772.25** ms, iframe-src 39.23 / 131.76 / 574.94 / 2469.55 / **9449.94** ms, ×4 per
|
||||
doubling for both. Under `[^><]*` the same inputs cost 0.08–0.66 ms and 0.10–1.00 ms: flat, not
|
||||
merely faster.
|
||||
|
||||
**Why this is not commons correcting seed data.** The dependency direction inverted. As of
|
||||
`llm-security` `be14867` their four injection tables are built from this file and hold zero local
|
||||
regex literals — measured on their published surface at `47905da`, with their vendored copy of
|
||||
the lexicon confirmed byte-identical to `0.7.0`. So re-extraction was not available as a
|
||||
mechanism: there is no upstream literal left to re-read. They re-measured the finding rather than
|
||||
accepting it, rejected `[^>]{0,256}` because a bound is paddable and `[^>]{1,256}` because it
|
||||
drops bare `<script>` and two corpus cases with it, chose `[^><]*`, and asked commons to carry
|
||||
it. Recorded in a new `source_fidelity.owner_directed_changes` block — deliberately **not** in
|
||||
`post_extraction_drift`, which would have said the source moved and commons followed, when the
|
||||
source now reads commons.
|
||||
|
||||
Not decided by majority. The guard reached `[^><]` first and independently (`cff0437`), so all
|
||||
three runtimes now agree, but a 3-of-3 count is not what moved this value and would not have
|
||||
been sufficient. The justification is the same one that kept commons on `[^>]` through `0.7.0`:
|
||||
this file tracks its declared source, and the declared source chose.
|
||||
|
||||
Accepted cost, stated plainly: content carrying a literal `<` between the tag name and the `>`
|
||||
(`<script <x>`, `<script<div>`) stops matching. Measured across **all 90** conformance cases,
|
||||
not only the four that cite these ids: zero lost a match, zero gained one. The dropped class is
|
||||
real and unwitnessed by the corpus.
|
||||
|
||||
- `signatures/secret-egress.json` `0.2.0` → `0.3.0` — **the one-entry staleness disclosed in
|
||||
`0.2.0` is closed by re-extraction, 18 → 19 patterns.** `OpenAI Legacy API Key`
|
||||
(`\bsk-[A-Za-z0-9]{20}T3BlbkFJ[A-Za-z0-9]{20}\b`) enters at `order` 17, second to last; `JWT
|
||||
(three-part token)` moves to 18 and stays last, which `ordering.last_entry_is_load_bearing`
|
||||
requires.
|
||||
|
||||
Read out of the module text at a pinned public commit, never transcribed from the coord message
|
||||
that reported it — the message contained the regex, and that is exactly the path
|
||||
`evidence_limits` had ruled out. `refs/heads/main` on the public remote is `47905da`; `088e458`
|
||||
carries the entry and was confirmed an ancestor with `git merge-base --is-ancestor` rather than
|
||||
read off their log.
|
||||
|
||||
A side effect worth more than the entry: **all 19 positions were compared against the module** —
|
||||
name, regex source, flags, order — with 0 divergences. Positions 0–16 came from a 2026-08-09
|
||||
transcription whose module fidelity had stood recorded as llm-security's assertion rather than a
|
||||
reproduced result. It is now reproduced, and that `evidence_limits` bullet is retired along with
|
||||
the staleness one.
|
||||
|
||||
- `conformance/manifest.json` `0.3.1` → `0.3.2` — the `secret-egress` blocker prose said its note
|
||||
would stand until the re-extraction landed. It landed, so item (2) (`openai-api-key-legacy` is a
|
||||
real hole here) is marked closed, and the entry count moves 18 → 19. **The blocker itself does
|
||||
not close**: 19 entries against the guard's 25 at different cut points is still a table
|
||||
reconciliation nobody has performed, and one closed hole is not that reconciliation.
|
||||
|
||||
- `docs/lexicon-port-divergence.md` (informative) — the `[^>]` vs `[^><]` row gets the number
|
||||
it never had for **this** side. The guard disclosed that their `[^><]` is a measured ReDoS fix
|
||||
(`cff0437`), not a preference, and asked commons to measure its own form rather than take
|
||||
their word. Measured here in Node and Python: `<script\b[^>]*>` is **quadratic** in scan
|
||||
position on input that denies it a `>` — ×4.0 per doubling, 6.7 s at 256 000 chars against
|
||||
0.41 ms for the guard's form.
|
||||
it never had for **this** side, and then gets closed. The guard disclosed that their `[^><]` is a
|
||||
measured ReDoS fix (`cff0437`), not a preference, and asked commons to measure its own form
|
||||
rather than take their word. Measured here in Node and Python: `<script\b[^>]*>` is **quadratic**
|
||||
in scan position on input that denies it a `>` — ×4.0 per doubling, 6.7 s at 256 000 chars
|
||||
against 0.41 ms for the guard's form.
|
||||
|
||||
Counted across the whole lexicon rather than assumed from the one row: 8 of 83 patterns carry
|
||||
a bare `[^>]`, six of them bounded (`{1,256}`, measured linear) and **two unbounded**. The
|
||||
second unbounded one, `hybrid-xss:iframe-src`, had not been named by any party — 16.9 s at
|
||||
256 000 chars.
|
||||
|
||||
**No data file is touched and neither pattern changes here.** Both are byte-identical to
|
||||
`llm-security`'s source, and behaviour preservation is not suspended because a measurement is
|
||||
unwelcome. The finding is routed to the owning runtime, which is what `SECURITY.md` promises
|
||||
an outsider would happen — this is the first time that route has been walked from the inside.
|
||||
The finding was routed to the owning runtime, which is what `SECURITY.md` promises an outsider
|
||||
would happen — the first time that route was walked from the inside. It came back as a decision
|
||||
the same day, and the document now records the closure with the invariant intact: the
|
||||
measurement travelled, the authority did not. Had `llm-security` declined, both rows would still
|
||||
read `[^>]*` and this file would record a permanent divergence instead.
|
||||
|
||||
## [0.3.1] — 2026-08-11
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue