Commit graph

8 commits

Author SHA1 Message Date
8ee297c585 feat(calibration): add calibration.json, marked transcribed-only
The risk-score tier constants, verdict thresholds, risk-band cutoffs and
posture grade thresholds. Constants only — the log scaling and the if/else
chains that consume them are engine and stay in the consumer.

This file is the exception in this repository and is marked as such in its
own verification block. Every other data file here was rebuilt from its
commons JSON and diffed against an imported module. This one arrived as a
human-written PROSE SUMMARY of severity.mjs, so there was nothing to import
and nothing to diff. verified: false, with the two skipped checks named
rather than a caveat attached to a pass.

The consequence inverts this repository's central rule and the file says so:
for every other file a disagreeing consumer is wrong; for this one, until the
module arrives in executable form, a disagreement is not automatically the
consumer's bug.

What COULD be checked was: bands are contiguous and non-overlapping across
0-100, the BLOCK trigger (65) is exactly the Critical band floor, the WARNING
trigger (15) is exactly the Medium band floor, and the per-tier reachable
minima recompute exactly (80/48/20/4, exact because log2(2) is 1).

Corrects README and the extraction plan in the same commit: both promised
entropy floors, scan caps and disposition ranks. None arrived — 0 occurrences
each across the whole dump. Named in the file under not_supplied so the
absence is visible rather than inferred, and both rows now describe what is
actually present.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FaYqid3mejFmd9ZHsiHgp3
2026-08-09 21:14:13 +02:00
dd6ae51d60 feat(mapping): add owasp-map.json from verified llm-security dump
Four parallel taxonomy maps — LLM, ASI (agentic), AST (skills) and MCP —
each keyed by the same 16 scanner prefixes, so a finding can be placed in
whichever taxonomy a report is written against.

Proven, not transcribed: each exported object was rebuilt from the commons
JSON alone and compared against the imported dump module — 4/4 identical on
keys, order, values and empty arrays. The shared 16-key order was verified
across all eight objects rather than assumed, and the count is the counted
one (the dump's own aside says 14).

Empty arrays are data and are preserved as arrays: agentic TRG/AST, skills
WFL/SIG, mcp WFL/TRG/SIG/AST all mean "deliberately mapped to nothing", not
"gap to fill".

Recorded as an open question in the file rather than papered over: the dump
does not state which EDITION of each taxonomy the codes belong to. OWASP's
LLM Top 10 was renumbered between editions — LLM06 is Excessive Agency in the
2025 list, with earlier entries consolidated and LLM07/LLM08 newly added — so
a bare LLM06 does not identify a risk. Two runtimes can match this map
perfectly and still disagree about what a finding means, which is the exact
failure this repository exists to prevent. taxonomy_name is left null rather
than guessed; the question goes to llm-security.

Scanner prefix meanings were not supplied and are reproduced as opaque keys.
Verification log in docs/extraction-plan.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FaYqid3mejFmd9ZHsiHgp3
2026-08-09 21:11:50 +02:00
c3852c9148 feat(signatures): add secret-egress.json from verified llm-security dump
The 18 fixed credential and token shapes a pre-write guard matches before
content is persisted: cloud keys, vendor tokens, PEM blocks, connection
strings, JWTs.

Proven, not transcribed: the table was rebuilt from the commons JSON alone
and diffed against the imported dump module — 18/18 identical on name, source
and flags, and all 18 byte-identical, so no normalisation was needed. All 18
compile in Node bare, Node under `u`, and Python `re`.

Array order is normative and is tested as such, not merely asserted: a Bearer
header containing a JWT must be labelled "Authorization header with token"
rather than "JWT (three-part token)", which is why the source puts the bare
JWT entry last. Reproduced from the commons order, and shown to change under a
reversed table. Every entry carries an explicit `order` field so a JSON
round-trip cannot reorder the contract silently.

Corrects the extraction plan's seed-source row in the same commit: it named
knowledge/secrets-patterns.md, but the dump named hooks/scripts/
pre-edit-secrets.mjs and stated the two are different tables. Recording a
source file that was never delivered is the defect class this repository
already caught once in finding.schema.json.

Neither severity nor disposition was supplied, so neither is invented — the
source table carries a name and a pattern and nothing else. Verification log
in docs/extraction-plan.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FaYqid3mejFmd9ZHsiHgp3
2026-08-09 21:10:01 +02:00
f4aa8b66f4 feat(codepoints): add carriers.json from verified llm-security dump
Six independent carrier tables: zero-width characters (5), the Unicode Tags
block with its subtraction decode rule, the two Supplementary Private Use
Areas, BIDI controls (9, the Trojan Source class CVE-2021-42574), the
Cyrillic presence set (13), and the fold-to-Latin homoglyph map (28).

Proven, not transcribed: five of the six tables were rebuilt from the commons
JSON alone and diffed against the imported dump module — every constant
identical, and the homoglyph map identical down to insertion order. Folding a
corpus through the rebuilt table and the source table gives identical results.

The tables overlap but are NOT merged, and cross_table_notes states each
divergence as fact: the zero-width carrier set includes U+00AD while the
lexicon's pattern class does not; the lexicon class holds U+0456 which
CYRILLIC_CONFUSABLES lacks, and CYRILLIC_CONFUSABLES holds U+0445 which the
class lacks. Reporting that to llm-security, not fixing it here.

Two honest limits, marked in the file rather than smoothed over: the private
use ranges arrived as a source comment with no constant behind them and carry
verified: false, and the dump's own "~25 entries" estimate for the homoglyph
map is wrong — counted mechanically it is 28.

Character names resolved through Python unicodedata against the Unicode
character database, not written from recollection. Verification log in
docs/extraction-plan.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FaYqid3mejFmd9ZHsiHgp3
2026-08-09 21:08:01 +02:00
23cf3e383a feat(lexicon): add injection-lexicon.json from verified llm-security dump
The four prompt-injection pattern families — 21 critical, 32 high, 22 medium,
8 hybrid — with per-pattern label, ECMAScript source and declared flags.

Data only. The dump names checkCognitiveLoadTrap and scanForInjection's
variant building (normalise → fold → rot13 → unicode-tag escalation) as
ENGINE logic that never moves here; they are absent by intent, not omission.

Proven, not transcribed: all four arrays were rebuilt from the commons JSON
alone and diffed against the imported dump module — 83/83 identical on label,
source and flags, 81 of them byte-identical. All 83 compile in Node bare, Node
under `u`, and Python `re`.

Two deliberate deviations from byte-identity, declared in the file: the
zero-width and Cyrillic character classes carried raw code points, four of
them invisible. Escaped to \uXXXX (the convention forbids raw invisible code
points outside conformance inputs — an unreviewable class is where a silent
false negative hides) and proven equivalent by differential match-set
comparison over 208 adversarial inputs, 832 comparisons, 0 differences.
Class membership was counted from the dump bytes: the zero-width class holds
4 code points and does NOT include U+00AD.

HYBRID_PATTERNS' severity was not supplied and is left null rather than
inferred from its siblings. Verification log in docs/extraction-plan.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FaYqid3mejFmd9ZHsiHgp3
2026-08-09 21:05:15 +02:00
0433240b14 feat(schema): add finding.schema.json with normative SARIF profile
The finding contract plus the SARIF 2.1.0 output profile, modelled on
llm-security's sarif-formatter.mjs (operator dump). Draft 2020-12, valid
against the metaschema.

The SARIF profile is proven, not transcribed: the mapping was re-implemented
from the commons JSON alone and diffed against the real toSARIF over 10
envelope shapes (all severities incl. unknown/undefined, slug edge cases,
rule-id collision, every optional-field combination, multi-scanner, explicit
version) — 0 differences.

Three things left honest rather than closed:
- additionalProperties stays open. The formatter CONSUMES findings, so fields
  it ignores are invisible in this evidence; the property list is a lower
  bound until the producer is supplied.
- The JSONL profile is status=unspecified with a TODO. "One finding per line"
  is inference, and a guessed normative contract is worse than a missing one.
- Node and the Python guard share only severity+owasp; the rest of the field
  names diverge (scanner/title vs detector/label). Recorded as an open
  question for v0.2.0, not settled silently here.

One published claim was wrong and is corrected: rule-id collision does NOT
cover punctuation, only case and whitespace runs. Caught by executing the
claim instead of asserting it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0191AKc2qW6tmXDFSx1xn53q
2026-08-09 14:52:53 +02:00
43f682bedd feat(signatures): add active-content.json from verified guard source
The EchoLeak class (CVE-2025-32711): markdown image/link/refdef/autolink,
data: URIs and active HTML, plus the URL-shape analysis that separates a URL
naming a remote document from one carrying bytes outward.

Seeded from llm-ingestion-pipeline-security v0.3.4 @ 0bf0729 (read-only) —
active_content.py's pattern table and calibration.py's severities/floors.
That module documents itself as the canonical home of this table, which is
why the guard is the source here rather than llm-security.

One deliberate deviation from byte-identity, recorded in the file: five
patterns carried `\"` from Python raw strings, which is a SyntaxError under
ECMAScript's u/v flags. Normalised to `"` and proven equivalent by
differential match-set comparison (5 patterns x 30 adversarial inputs, 0
differences). Verification log in docs/extraction-plan.md.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0191AKc2qW6tmXDFSx1xn53q
2026-08-09 14:37:48 +02:00
ef80288c57 feat: initialize llm-security-commons (charter, license, extraction plan)
Data+contract+fixtures repository for runtime-neutral LLM/agent security
detection. Charter is hard: no engine code, no dependencies, no runtime —
JSON data, normative specs and conformance fixtures only.

Scaffolding only; the seed data files land in follow-up commits from
verified source dumps (never from recollection).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0191AKc2qW6tmXDFSx1xn53q
2026-08-09 14:29:16 +02:00