docs(divergence): our own form has a number now, and it is quadratic
The guard answered the span-byte question with evidence rather than preference: their [^><] is a measured ReDoS fix (cff0437, 2026-07-31), and they asked us to measure our form rather than take their word for it. We did. Node v25.8.2 and Python 3.14.0, patterns read out of the lexicon, run over '<script ' repeated — the unit that denies the pattern the > it needs: 25.5ms at 16k chars, 6681.6ms at 256k. x4.0 per doubling against the guard form's x2. Quadratic against linear, reproduced in both engines. It is scan-position quadratic, not catastrophic backtracking: <script matches at ~n positions and [^>]* scans to end of input at each one. Counted across the whole file instead of stopping at the row we were told about: 8 of 83 patterns carry a bare [^>], none carries [^><]. Six are the bounded html-obfuscation family — measured linear, so bounding does work, at the recall cost this file already records. Two are unbounded, and the second one, hybrid-xss:iframe-src, had not been named by any party: 16.9s at 256k chars. That row is ours, found by counting rather than by being told. No data file touched. Both patterns stay byte-identical to llm-security's source, because behaviour preservation is not suspended when a measurement is unwelcome — commons carries [^>] on provenance and would carry [^><] had the source been the guard's. The finding is routed to the owning runtime instead, which is exactly the path SECURITY.md promised an outsider three commits ago. First time that route is walked from the inside. Also recorded: the guard's own disclosure that their suite passes under both forms (717 green), because their DoS row repeats '<script>' — which supplies the > and never exercises the run. Verified: JSON well-formed, every spec still normative, charter clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T85QqeiWBEoBMjWaMiBnxD
This commit is contained in:
parent
0e765a02eb
commit
4187715ab7
2 changed files with 71 additions and 0 deletions
19
CHANGELOG.md
19
CHANGELOG.md
|
|
@ -11,6 +11,25 @@ case ids, disposition semantics). Each JSON file additionally carries its own
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
### Changed
|
||||
|
||||
- `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.
|
||||
|
||||
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.
|
||||
|
||||
## [0.3.1] — 2026-08-11
|
||||
|
||||
**No pattern changed value. One shipped table is disclosed as stale, and the repository gains
|
||||
|
|
|
|||
|
|
@ -242,6 +242,58 @@ disagreement — not an oversight on either side.
|
|||
Neither strategy is free, and neither is obviously right. That is the decision the two owning
|
||||
repositories have to take, and it is not commons' to take for them.
|
||||
|
||||
### The cost of commons' strategy, measured here — 2026-08-11
|
||||
|
||||
The section above says neither strategy is free and neither is obviously right. That was
|
||||
written without a number for **this** side's cost. There is one now, and it is not symmetric
|
||||
with the guard's.
|
||||
|
||||
The prompt came from the guard (coord, 2026-08-11): their `[^><]` is not a preference but a
|
||||
measured ReDoS fix (`cff0437`, 2026-07-31), and they asked commons to measure its own form
|
||||
rather than take their word. Measured here — Node v25.8.2 and Python 3.14.0, Intel i9-9880H,
|
||||
patterns read out of `lexicon/injection-lexicon.json` and run over `'<script '` repeated,
|
||||
the unit that denies the pattern the `>` it needs:
|
||||
|
||||
| chars | `<script\b[^>]*>` (commons, Node) | `<script\b[^><]*>` (guard form, Node) |
|
||||
|---|---|---|
|
||||
| 16 000 | 25.5 ms | 0.08 ms |
|
||||
| 32 000 | 101.3 ms | 0.06 ms |
|
||||
| 64 000 | 413.5 ms | 0.12 ms |
|
||||
| 128 000 | 1 676.5 ms | 0.24 ms |
|
||||
| 256 000 | 6 681.6 ms | 0.41 ms |
|
||||
|
||||
×4.0 per doubling against ×2 — quadratic against linear, reproduced in Python `re` on the same
|
||||
inputs (0.021 s → 5.44 s over the same range, guard form 0.0001 s → 0.0015 s). It is
|
||||
scan-position quadratic, not exponential backtracking: `<script` matches at ~n positions and
|
||||
`[^>]*` scans to end of input at each one. Nothing here is catastrophic backtracking, and
|
||||
nothing here needs a nested quantifier to happen.
|
||||
|
||||
**Two of the 83 patterns have this shape, not one.** Counted over the whole file, 8 patterns
|
||||
carry a bare `[^>]` and none carries `[^><]`. Six of the 8 are the html-obfuscation family and
|
||||
are **bounded** (`[^>]{1,256}`) — measured linear (51 → 164 ms across a 8× input growth), so
|
||||
bounding does work as a mitigation, at the recall cost the section above already records. The
|
||||
other two are unbounded `[^>]*`:
|
||||
|
||||
- `hybrid-xss:script-tag` — the row this file already tracks.
|
||||
- `hybrid-xss:iframe-src` — **not previously named by anyone**, found here by counting rather
|
||||
than by being told. Same shape, same result: 119.6 ms → 16 857 ms over 32 000 → 256 000
|
||||
chars of `'<iframe '`.
|
||||
|
||||
What this does and does not license:
|
||||
|
||||
- It does **not** license changing either pattern here. Both are byte-identical to
|
||||
`llm-security`'s source, and the behaviour-preservation invariant is not suspended because
|
||||
the measurement is unwelcome. Commons carries `[^>]` on provenance and would carry `[^><]`
|
||||
had the source been the guard's — that was true before this measurement and stays true after.
|
||||
- It does mean the finding is **owed to the owning runtime**, which is `llm-security` for both
|
||||
patterns. Sent 2026-08-11, with these numbers and the `iframe-src` row they did not have.
|
||||
- The guard's own honest disclosure belongs on the record too: their suite passes under both
|
||||
forms (717 green), because the DoS row that ought to discriminate uses `'<script>'` as its
|
||||
repeating unit, which supplies the `>` and never exercises the run. The invariant is
|
||||
documented there and not test-enforced. A conformance case could hold it — but a fixture that
|
||||
pins a *timing* property is a different kind of case from anything in this corpus today, and
|
||||
minting one is not commons' call to take alone.
|
||||
|
||||
## Severity: the 8 hybrid patterns
|
||||
|
||||
**Resolved 2026-08-09. The two sides never disagreed; only the evidence did.**
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue