fix(lexicon): converge script-tag on its source — re-extraction, not revision
hybrid-xss:script-tag drops the closing-tag requirement, becoming byte-identical to llm-security's RegExp.source at b1ba1fb (injection-patterns.mjs:170). Verified by compiling both, not by reading them. Why this does not breach behaviour-preservation: that invariant forbids commons from CORRECTING seed data it believes is wrong. It does not forbid re-reading the source after the source itself moved and its owner asked. This file's declared provenance is llm-security's injection table, and being loadable verbatim by that table's owner is the one thing it exists to do. The standing alternative was a per-pattern override in their loader — a published core its own source repository could not load as published. Direction is what makes it safe: the new form matches a strict superset of the old, so it can add matches and cannot introduce a false negative. The reverse change would not have been adoptable on this reasoning. NOT decided by the 2-of-3 majority across the three ports. A count of implementations is not a mandate over detection data; the provenance argument would hold with the guard on either side. Operator decision, 2026-08-11, on llm-security's blocking coord request (their 10:46:28Z message, step-4 swap parked behind it). Measured collateral: none. Full corpus run under both patterns — 84/84 lexicon-scoped cases pass under 0.7.0, and exactly one case's finding set differs between the forms. The widening added no finding to any other case's input. source_fidelity keeps patterns_byte_identical_to_source at 83 and gains the field it was missing: byte_identical_against_commit: b1ba1fb. Against the original extraction commit b0de0ca the count is now 82/83, recorded explicitly. post_extraction_drift is marked resolved and carries before/after pattern text, so a consumer diffing against either commit has a coordinate for what it finds. The divergence row is closed on the closing-tag axis after reversing twice in three days. What stays open is the one-byte span difference: the guard excludes `<` from its negated class and the other two do not, so `<script <x>` matches commons and llm-security but not the guard. Measured by compiling all three. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HuudQLGMyMenuyeZk8fKs5
This commit is contained in:
parent
6f79a6ea57
commit
c1b2385de6
2 changed files with 56 additions and 13 deletions
|
|
@ -145,11 +145,39 @@ guard's excluded-character class also excludes `<`, `llm-security`'s does not. T
|
|||
difference is unresolved on both sides (see *Open questions* in the coordination thread); it
|
||||
does not reopen the closing-tag question, which is settled.
|
||||
|
||||
Commons still carries the pre-`90f576f` form, unchanged, per this repository's
|
||||
behaviour-preservation invariant — commons does not follow either upstream regex change
|
||||
without an operator decision to re-extract. **Commons is now the sole diverger of the three**
|
||||
on the closing-tag requirement: both `llm-security` and the guard match `<script src=x.js>`
|
||||
and unclosed `<script>alert(1)`; commons' extracted pattern still requires `</script>`.
|
||||
**Commons converged in lexicon `0.7.0` (2026-08-11), and this row is closed on the closing-tag
|
||||
axis.** Through `0.6.0` commons was the sole diverger of the three: both `llm-security` and the
|
||||
guard matched `<script src=x.js>` and unclosed `<script>alert(1)`, and commons' extracted pattern
|
||||
still required `</script>`. Commons now carries `<script\b[^>]*>` — byte-identical to
|
||||
`llm-security`'s `RegExp.prototype.source` at `b1ba1fb`, verified by compiling both.
|
||||
|
||||
The decision was **re-extraction, not revision**, and the distinction is what made it available
|
||||
at all under the behaviour-preservation invariant. That invariant forbids commons from correcting
|
||||
seed data it believes is wrong; it does not forbid re-reading the source after the source itself
|
||||
moved and its owner asked. The lexicon's declared provenance is `llm-security`'s injection table,
|
||||
and being loadable verbatim by that table's owner is the one thing it exists to do — the standing
|
||||
alternative was a per-pattern override in `llm-security`'s own loader, i.e. a published core that
|
||||
its source repository could not load as published. Operator decision, 2026-08-11, on
|
||||
`llm-security`'s blocking coord request. Explicitly **not** decided by the 2-of-3 majority: a
|
||||
count of implementations is not a mandate over detection data, and the provenance argument would
|
||||
have held with the guard on either side.
|
||||
|
||||
The direction matters for what it cannot break: the new form matches a strict superset of the old
|
||||
one, so relative to `0.6.0` it can add matches and cannot add a false negative. The reverse change
|
||||
would not have been adoptable on the same reasoning.
|
||||
|
||||
**What is still open is the one-byte span difference**, and convergence did not touch it. The
|
||||
guard excludes `<` from its negated class and the other two do not, so:
|
||||
|
||||
| Witness | commons `0.7.0` / `llm-security` | guard |
|
||||
| --- | --- | --- |
|
||||
| `<script>steal()</script>` | match | match |
|
||||
| `<script src=x.js>` | match | match |
|
||||
| `<script>alert(1)` | match | match |
|
||||
| `<script <x>` | **match** | **no match** |
|
||||
|
||||
Measured by compiling all three forms, not reasoned from the character classes. The last row is
|
||||
the whole residual divergence and neither side has claimed it.
|
||||
|
||||
## Why they diverge: two different ReDoS mitigations of one table
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue