docs(divergence): the span row had one witness; llm-security measured five more
Their coord message of 2026-08-11T11:01:59Z measured the three <script> forms as totally ordered by what they match — [^>] strictly contains [^><] strictly contains the pre-0.7.0 closing-tag form — and named two input classes the guard's narrower class drops that commons had not recorded: `<script a="<" >x` and `<script<div>`. Reproduced independently before writing it down, including the strict-superset property in both directions. Their table came with a claim attached; the claim is now a measurement here rather than a relayed assertion. Their argument for [^>] — the narrower class buys an empty false-positive surface, since anything reaching [^>]-and-not-[^><] already contains a literal <script tag — is recorded as THEIRS and marked explicitly as not what decided commons' form. Commons carries [^>] on provenance and would have carried [^><] had the source been the guard's. Keeping that distinction visible matters more than the regex: if merit ever becomes the reason a commons pattern moves, behaviour-preservation is gone. Also records honestly that they asked to hear the guard's reason for [^><] before commons shipped, and commons shipped first — with why that order is defensible rather than an oversight. A reason that beats their argument is a reason for the guard's own port; commons would still track its declared source. Informative file only. v0.3.0 unaffected. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HuudQLGMyMenuyeZk8fKs5
This commit is contained in:
parent
4641a7b518
commit
d96fbbf791
2 changed files with 47 additions and 12 deletions
18
CHANGELOG.md
18
CHANGELOG.md
|
|
@ -11,7 +11,23 @@ case ids, disposition semantics). Each JSON file additionally carries its own
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
Nothing yet.
|
||||
### Changed
|
||||
|
||||
- `docs/lexicon-port-divergence.md` (informative) — the residual `[^>]` vs `[^><]` row gains a
|
||||
fuller witness set. `llm-security` measured the three forms as **totally ordered** by what they
|
||||
match, each a strict superset of the next, and named two input classes the guard's narrower
|
||||
class drops (`<script a="<" >x`, `<script<div>`) beyond the one commons had recorded.
|
||||
Reproduced here independently, including the strict-superset property in both directions,
|
||||
before being written down.
|
||||
|
||||
Their argument — that the narrower class buys an empty false-positive surface, since anything
|
||||
reaching `[^>]`-and-not-`[^><]` already contains a literal `<script` tag — is recorded as
|
||||
theirs and explicitly **not** what decided commons' form. Commons carries `[^>]` on provenance,
|
||||
and would have carried `[^><]` had the source been the guard's. Also records that they asked to
|
||||
hear the guard's reason for `[^><]` before commons shipped and commons shipped first, with why
|
||||
that order was deliberate.
|
||||
|
||||
No data file touched; `v0.3.0` is unaffected.
|
||||
|
||||
## [0.3.0] — 2026-08-11
|
||||
|
||||
|
|
|
|||
|
|
@ -167,17 +167,36 @@ one, so relative to `0.6.0` it can add matches and cannot add a false negative.
|
|||
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:
|
||||
guard excludes `<` from its negated class and the other two do not. The three forms turn out to
|
||||
be **totally ordered by what they match** — each a strict superset of the next:
|
||||
|
||||
| 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** |
|
||||
| Witness | commons `0.7.0` / `llm-security` `[^>]` | guard `[^><]` | commons ≤ `0.6.0` |
|
||||
| --- | --- | --- | --- |
|
||||
| `<script>steal()</script>` | match | match | match |
|
||||
| `<script src=x.js>` | match | match | no match |
|
||||
| `<script>alert(1)` | match | match | no match |
|
||||
| `<script\n src=x>` | match | match | no match |
|
||||
| `<script a="<" >x` | **match** | **no match** | no match |
|
||||
| `<script<div>` | **match** | **no 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.
|
||||
Measured by compiling all three forms, not reasoned from the character classes. The last two rows
|
||||
are the whole residual divergence.
|
||||
|
||||
The witness set and the ordering observation are `llm-security`'s, from their coord message of
|
||||
2026-08-11T11:01:59Z; both were **reproduced here independently** before being recorded, including
|
||||
the strict-superset property in both directions. Their reading of it: `[^><]` refuses to cross a
|
||||
`<`, and since anything that reaches `[^>]`-and-not-`[^><]` already contains a literal `<script`
|
||||
opening tag, the narrower class buys an empty false-positive surface in exchange for two dropped
|
||||
input classes — a recall loss with no precision gain to trade for.
|
||||
|
||||
**That argument is recorded, not endorsed, and it did not decide commons' form.** Commons carries
|
||||
`[^>]` because the lexicon's declared provenance is `llm-security`'s table (see above), not
|
||||
because their regex won on merit — the same reasoning would have taken commons to `[^><]` had the
|
||||
source been the guard's. `llm-security` asked to hear the guard's reason for `[^><]` — a ReDoS
|
||||
bound, or a span-extraction consumer needing the run to stop at `<` — before commons shipped, and
|
||||
commons shipped first. That order is deliberate rather than an oversight: a reason that beats this
|
||||
argument is a reason for the *guard's own port*, and commons would still track its declared
|
||||
source. Put to the guard as an open question 2026-08-11; unanswered at time of writing.
|
||||
|
||||
## Why they diverge: two different ReDoS mitigations of one table
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue