llm-security/tests/lib
Kjell Tore Guttormsen be148671ee feat(llm-security): swap injection tables to vendored commons lexicon
Third consumer swap of v8 Phase 5 step 4, after codepoints and OWASP_MAP,
and the last one with a behavioural gate behind it. The 83 regex literals
leave injection-patterns.mjs; the four arrays are now built in
scanners/lib/injection-lexicon.mjs from the vendored
lexicon/injection-lexicon.json and re-exported unchanged, so every
consumer sees the same published surface.

Behaviour-preserving by measurement, not by intent. The proven recipe ran
in order: a differential over all 83 positions (regex source, flags,
label, aliases.llm_security) found 0 divergences BEFORE anything changed;
the golden dump was then diffed post-for-post rather than read as a 9000-
character assertion, and the ONLY changed record was the sha256 of
injection-patterns.mjs itself -- 83 regex posts, 7 table records and all
counts identical. That single file digest is the diff a swap MUST produce,
so the baseline was re-blessed rather than silenced.

Two deliberate departures from the two earlier swaps:

FAILURE IS LOUD. codepoints and owasp-map fail silently on purpose: an
empty codepoint table weakens normalization, an empty OWASP map mislabels
a report. An empty injection table is different in kind -- scanForInjection
returns found:false for every input, and the UserPromptSubmit scan, the
MCP output scan and the pre-compact scan all go blind while reporting
success. That is precisely the v7.8.2 defect class, which bit this plugin
four times in one release. An unresolvable commons therefore writes one
line to stderr naming the disabled capability. It still does not throw:
hooks run per-tool-call, and a module-load throw breaks the tool call
instead of degrading the scan. The warning is suppressed for an explicit
commonsRoot, so tests and dev checkouts stay quiet and the line keeps
meaning something.

ENTRIES COMPILE DEFENSIVELY. commons is vendored data, not code. An
uncompilable pattern or unknown flag would throw inside new RegExp at
module load -- in a hook. Malformed entries are dropped instead, the same
call owasp-map.mjs makes for a non-array value.

Gates proven by mutating the vendored JSON in BOTH directions, five ways,
all firing: re-adding the script-tag tail commons dropped (golden 1,
lexicon 2, corpus 1), dropping a critical pattern (2/1/3), stripping the
`m` flag off a spoofed-header anchor (2/1), adding a pattern commons never
published (2/2/85), and removing commons outright -- which produced the
stderr line, four empty tables and 5 red rather than a green suite over
zero patterns. Lexicon restored byte-identical after each.

Full suite 2191 pass / 0 fail / 6 skipped (2184 -> 2197).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017XDdiKC9ZXmcSUQ2m84s6y
2026-08-11 14:13:36 +02:00
..
audit-trail.test.mjs feat(llm-security)!: v8 Phase 3 step 1 - remove the deprecated mode env-vars 2026-08-09 10:17:47 +02:00
bash-normalize.test.mjs feat(ultraplan-local): v1.6.0 — /ultraresearch-local deep research command 2026-04-08 08:58:35 +02:00
build-zip.mjs feat(llm-security): /security ide-scan <url> — Marketplace/OpenVSX/direct VSIX (v6.4.0) 2026-04-17 17:16:26 +02:00
codepoints.test.mjs refactor(llm-security): v8 Phase 5 step 4 - swap codepoint tables to commons 2026-08-10 21:28:09 +02:00
commons-loader.test.mjs test(llm-security): v8 Phase 5 step 3 - invert the unvendored-commons test 2026-08-10 20:52:04 +02:00
conformance-corpus.test.mjs chore(llm-security): pull commons subtree to v0.3.0, corpus 89 -> 90 cases 2026-08-11 14:05:07 +02:00
diff-engine-exact-pass.test.mjs fix(llm-security): misc scanner correctness — reflog FP, diff exact-pass, hex dedupe, SARIF version (#20,#22,#50,#54,#56) 2026-07-18 10:36:51 +02:00
distribution-stats.test.mjs feat(ultraplan-local): v1.6.0 — /ultraresearch-local deep research command 2026-04-08 08:58:35 +02:00
doc-consistency.test.mjs docs(llm-security): trim README badge row 8 -> 4 (repo-standard BADGE-COUNT) 2026-08-04 11:50:12 +02:00
file-discovery.test.mjs fix(llm-security): normalization/discovery evasion + SIG embedded-base64 & custom rules (#21,#23,#30,#36,#42,#52,#55) 2026-07-18 10:35:56 +02:00
git-clone-gitattributes.test.mjs feat(git-clone): E12 — .gitattributes filter-driver post-clone advisory 2026-04-30 15:29:13 +02:00
git-clone-sandbox.test.mjs feat(ultraplan-local): v1.6.0 — /ultraresearch-local deep research command 2026-04-08 08:58:35 +02:00
golden-baseline.test.mjs fix(llm-security): golden gate - coverage block measured something else 2026-08-09 13:06:45 +02:00
injection-lexicon.test.mjs feat(llm-security): swap injection tables to vendored commons lexicon 2026-08-11 14:13:36 +02:00
injection-patterns.test.mjs fix(llm-security): v8.x-A - close <script> recall hole, add whole-table ReDoS gate 2026-08-10 14:53:29 +02:00
mcp-description-cache.test.mjs fix(llm-security): scanner robustness — ReDoS, MCP-stdout DoS, redirect loop, atomic writes (#24,#53,#31,#25,#51) 2026-07-18 10:15:11 +02:00
output.test.mjs feat(llm-security)!: v7.0.0 commit 6 — tests, docs, version bump 2026-04-19 22:26:35 +02:00
owasp-map.test.mjs refactor(llm-security): v8 Phase 5 step 4 - swap OWASP_MAP to commons 2026-08-11 12:53:48 +02:00
policy-loader.test.mjs feat(llm-security)!: v8 Phase 3 step 1 - remove the deprecated mode env-vars 2026-08-09 10:17:47 +02:00
severity.test.mjs docs(severity): B3 — document info as scoring-inert (v7.2.0 prep) 2026-04-29 13:56:11 +02:00
skill-registry-atomic.test.mjs fix(llm-security): scanner robustness — ReDoS, MCP-stdout DoS, redirect loop, atomic writes (#24,#53,#31,#25,#51) 2026-07-18 10:15:11 +02:00
string-utils-hidden-unicode.test.mjs feat(unicode): E1 — extend hidden-Unicode detection to PUA-A and PUA-B 2026-04-29 14:18:49 +02:00
string-utils-homoglyph.test.mjs feat(injection): E16 — homoglyph NFKC fold before every pattern match 2026-04-29 14:22:05 +02:00
string-utils-tokens.test.mjs fix(dep): B7 — token-overlap typosquat heuristic alongside Levenshtein 2026-04-29 14:10:53 +02:00
string-utils.test.mjs fix(llm-security): normalization/discovery evasion + SIG embedded-base64 & custom rules (#21,#23,#30,#36,#42,#52,#55) 2026-07-18 10:35:56 +02:00
v8-env-removal.test.mjs feat(llm-security)!: v8 Phase 3 complete - riskScoreV1, posture heuristic, docs 2026-08-09 10:25:03 +02:00
workflow-yaml-state.test.mjs fix(llm-security): YAML/workflow parser divergence — block scalars + bare if: (#32,#33,#43) 2026-07-18 10:35:56 +02:00
yaml-frontmatter.test.mjs fix(llm-security): YAML/workflow parser divergence — block scalars + bare if: (#32,#33,#43) 2026-07-18 10:35:56 +02:00