Skip to content

fix: close control_id↔registry join gap (M2) — 331→0 misses, registry-aware parser + reconciliation - #218

Merged
emmanuelgjr merged 10 commits into
mainfrom
fix/control-id-registry-join
Jun 10, 2026
Merged

fix: close control_id↔registry join gap (M2) — 331→0 misses, registry-aware parser + reconciliation#218
emmanuelgjr merged 10 commits into
mainfrom
fix/control-id-registry-join

Conversation

@emmanuelgjr

Copy link
Copy Markdown
Owner

What & why

Closes the machine-readable join gap (audit finding M2): previously 331 of ~3,351 entry mappings had a control_id that didn't resolve to any control in its framework's registry, so the classifier's ground truth and the web-app control-level pivots couldn't link them. validate.js never caught this because nothing checked the join. This PR drives join-misses to 0 and adds a hard-error guard so it can't silently reopen.

Built with a registry-aware parser + per-framework reconciliation. Each step gated on a new audit oracle (scripts/audit-control-join.mjs).

⚠️ Headline change to flag: control count 1,511 → 1,016 (−495)

This is intentional and traceable, not data loss — the mapping count is unchanged (3,351) and no entry lost a mapping:

  • −305 orphaned parser-bug sentence artifacts removed from SOC 2 / EU AI Act / 800-218A registries (the old parser had extracted prose mapping-descriptions into control_id, and those got captured into the registries as fake "controls"). Removed only controls that are both unreferenced by any mapping and a ≥6-word sentence not led by a formal code (safety-asserted: no referenced or formal-code control touched).
  • −~190 net from collapsing three prose-keyed registries onto authoritative formal codes (NHI 117→10, AI Testing Guide 58→9, NIST 800-82 →11), partially offset by +9 FedRAMP 800-53 top-up and +5 SOC2/EU/800-218A codes that were genuinely missing.

CWE/CVE and other frameworks have unreferenced registry entries that may be legitimate (e.g. real CWE names) — deliberately left untouched / deferred rather than risk deleting valid content.

Changes (10 commits)

Commit What
test(audit) scripts/audit-control-join.mjs — the join oracle (baseline 331)
fix(generate) registry-aware parser assigns control_id from whichever column token matches the framework registry; SOC2/EU-AI-Act/800-218A → 0
fix(nhi) re-key OWASP NHI registry → NHI-1..10 (verified vs official OWASP NHI Top 10)
fix(generate) section bound extractSection stops at the next ##/### so the last entry on a page no longer swallows trailing ## …/Changelog tables (this also fixed the AIUC-1 version/date rows)
fix(aitg) re-key AI Testing Guide → category codes (ACT/AST/AVT/DPT/IHT/LMT/MBT/OHT/SCT)
fix(800-82) re-key NIST SP 800-82 → §-section codes; also separated mislabeled 800-53 control blocks
fix(fedramp) top-up registry with 9 missing 800-53 controls → TOTAL misses 0
fix(registry) orphan cleanup remove 305 sentence-artifacts from SOC2/EU/800-218A
feat(validate) hard-error if any mapping control_id not in its registry (+1 check, 386 passed)
docs propagate 1,511 → 1,016 across README/CITATION/banner/og-image

Verification (final whole-branch review, all pass)

  • node scripts/audit-control-join.mjsTOTAL join-misses: 0
  • node scripts/validate.js0 errors / 386 passed (was 385 + the new check)
  • Negative test: corrupting a mapping control_id → validator errors + exit 1; restored → clean
  • node scripts/generate.js idempotent (the only "diff" is core.autocrlf CRLF noise, disproved by byte-compare)
  • Re-keyed registries hold authoritative codes (NHI-1..10, AITG categories, §-sections); FedRAMP top-up uses genuine 800-53 IDs — none invented
  • No entry lost all its mappings; mapping count unchanged at 3,351

Deliberately out of scope (deferred)

  • Orphaned unreferenced entries in CWE/CVE and other frameworks (may be legitimate — needs per-framework review)
  • One cosmetic under-indent in the generate.js if(!controlId) wrap (functionally correct)
  • Optional .gitattributes (*.json text eol=lf) to silence Windows CRLF noise

🤖 Generated with Claude Code

…'t misparsed

extractSection returned to EOF for the last entry on a page, so standalone
trailing sections (## … maturity, ## See also, ## Changelog) were swept into
that entry and their tables misparsed as control mappings. Stop at the next
## or ### heading. Clears the residual NHI maturity/changelog leaks and the
AIUC-1 version/date rows (join-misses 170 -> 99); removes ~16 spurious mappings.
… SOC2/EU-AI-Act/800-218A

The old (pre-fix) parser extracted prose mapping descriptions into control_id;
those got captured into 3 registries as sentence-keyed 'controls'. After the
registry-aware parser fix, mappings use formal codes, orphaning the sentences.
Removed only controls that are BOTH unreferenced by any mapping AND a >=6-word
sentence not led by a formal code (safety-asserted: no referenced or formal-code
control removed). SOC 2 212->46, EU AI Act 146->47, NIST 800-218A 53->13.
Scoped to these 3 (their legit controls are all formal-code-keyed); CWE/CVE and
others have unreferenced entries that may be legitimate -> deferred.
Join-misses still 0; validate 0/0/385.
@github-actions

Copy link
Copy Markdown
Contributor

🛡️ OWASP GenAI Security Crosswalk

This PR modifies 18 AI-related file(s). The following OWASP GenAI risks may be relevant:

Risk Entry Files Action
ASI01 Agent Goal Hijack data/entries/LLM01.json, data/entries/LLM02.json, data/entries/LLM03.json View controls
ASI02 Tool Misuse data/entries/LLM01.json, data/entries/LLM02.json, data/entries/LLM03.json View controls
ASI03 Credential Misuse data/entries/LLM01.json, data/entries/LLM02.json, data/entries/LLM03.json View controls
ASI04 Supply Chain data/entries/LLM01.json, data/entries/LLM02.json, data/entries/LLM03.json View controls
ASI05 Code Execution data/entries/LLM01.json, data/entries/LLM02.json, data/entries/LLM03.json View controls
DSGAI01 Data Leakage data/entries/LLM01.json, data/entries/LLM02.json, data/entries/LLM03.json View controls
DSGAI04 RAG Poisoning data/entries/LLM01.json, data/entries/LLM02.json, data/entries/LLM04.json View controls
DSGAI08 Configuration & Deployment data/entries/LLM01.json, data/entries/LLM02.json, data/entries/LLM03.json View controls
LLM01 Prompt Injection data/entries/LLM01.json, data/entries/LLM02.json, data/entries/LLM03.json View controls
LLM02 Sensitive Information Disclosure data/entries/LLM01.json, data/entries/LLM02.json, data/entries/LLM03.json View controls
LLM03 Supply Chain data/entries/LLM02.json, data/entries/LLM03.json, data/entries/LLM04.json View controls
LLM04 Data & Model Poisoning data/entries/LLM01.json, data/entries/LLM02.json, data/entries/LLM03.json View controls
LLM06 Excessive Agency data/entries/LLM01.json, data/entries/LLM03.json, data/entries/LLM05.json View controls
LLM07 System Prompt Leakage data/entries/LLM01.json, data/entries/LLM03.json, data/entries/LLM04.json View controls
LLM09 Misinformation data/entries/LLM01.json, data/entries/LLM09.json, docs/backlinks.js View controls

🔍 Scanned 62 changed files · Found 15 potential risks · Full crosswalk · Gap analysis

@emmanuelgjr
emmanuelgjr merged commit 9667524 into main Jun 10, 2026
9 checks passed
@emmanuelgjr
emmanuelgjr deleted the fix/control-id-registry-join branch June 10, 2026 18:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant