Skip to content

chore(deps): Bump ip-address and express-rate-limit in /frontend#19

Open
dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/npm_and_yarn/frontend/multi-7bdfbe8666
Open

chore(deps): Bump ip-address and express-rate-limit in /frontend#19
dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/npm_and_yarn/frontend/multi-7bdfbe8666

Conversation

@dependabot

@dependabot dependabot Bot commented on behalf of github May 14, 2026

Copy link
Copy Markdown

Bumps ip-address and express-rate-limit. These dependencies needed to be updated together.
Updates ip-address from 10.0.1 to 10.2.0

Commits

Updates express-rate-limit from 8.2.1 to 8.5.1

Release notes

Sourced from express-rate-limit's releases.

v8.5.1

You can view the changelog here.

v8.5.0

You can view the changelog here.

v8.4.1

You can view the changelog here.

v8.4.0

You can view the changelog here.

v8.3.2

You can view the changelog here.

v8.3.1

You can view the changelog here.

v8.3.0

You can view the changelog here.

Commits
Maintainer changes

This version was pushed to npm by GitHub Actions, a new releaser for express-rate-limit since your current version.


Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


Dependabot commands and options

You can trigger Dependabot actions by commenting on this PR:

  • @dependabot rebase will rebase this PR
  • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
  • @dependabot show <dependency name> ignore conditions will show all of the ignore conditions of the specified dependency
  • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    You can disable automated security fix PRs for this repo from the Security Alerts page.

Bumps [ip-address](https://github.com/beaugunderson/ip-address) and [express-rate-limit](https://github.com/express-rate-limit/express-rate-limit). These dependencies needed to be updated together.

Updates `ip-address` from 10.0.1 to 10.2.0
- [Commits](https://github.com/beaugunderson/ip-address/commits)

Updates `express-rate-limit` from 8.2.1 to 8.5.1
- [Release notes](https://github.com/express-rate-limit/express-rate-limit/releases)
- [Commits](express-rate-limit/express-rate-limit@v8.2.1...v8.5.1)

---
updated-dependencies:
- dependency-name: ip-address
  dependency-version: 10.2.0
  dependency-type: indirect
- dependency-name: express-rate-limit
  dependency-version: 8.5.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot dependabot Bot added dependencies Dependency updates javascript Pull requests that update javascript code labels May 14, 2026
eastmadc added a commit that referenced this pull request May 14, 2026
…maliser

Sub-task #2 of λ.α.D (Issue #11). Mirrors the existing
``memory_dump_walk_*`` / ``registry_hive_walk_*`` / 19 other per-walker
state-machine column families already on ``firmware``.

Alembic ``c5f6a7b8c9d0_add_windows_info_walk_status.py``:

- Chains from λ.α.B head ``bdf2a3b4c5d6``.
- Adds 5 columns on ``firmware``:
  ``windows_info_walk_status`` (str(20), NOT NULL, server_default
  ``idle``), ``_started_at`` (DateTime tz, nullable), ``_finished_at``
  (DateTime tz, nullable), ``_error`` (Text, nullable), ``_result``
  (JSONB, nullable).
- Rule #33 .c CHECK constraint ``ck_firmware_windows_info_walk_status``
  enforcing ``status IN ('idle', 'queued', 'running', 'completed',
  'failed')``.
- Revision ID ``c5f6a7b8c9d0`` was pre-validated FREE against the
  existing 125 revisions (Rule #19 evidence-first).

ORM (``backend/app/models/firmware.py``):

- 5 ``Mapped`` column declarations matching the migration. Placed
  directly after the λ.α.B ``memory_dump_walk_*`` block so the
  per-walker state-machine group stays clustered for grep / IDE
  navigation.

JSONB normaliser pair (``backend/app/services/jsonb_normalizers.py``):

- ``FIRMWARE_WINDOWS_INFO_WALK_RESULT_SCHEMA_VERSION = 1``.
- ``_normalize_firmware_windows_info_walk_result(value)`` — canonical
  pass-through, None preserved, wrong-typed values collapse to None
  per Rule #35c defensive boundary.
- ``_stamp_firmware_windows_info_walk_result(payload)`` — idempotent
  schema_version stamp. Added at writer-introduction time per Rule
  #35c forward-looking discipline (3+ consumer files projected at
  λ shipping: λ.α.D walker writer, λ.δ MCP tool reader, λ.ε frontend
  hub reader). Mirrors ``_stamp_firmware_registry_hive_walk_result``.

Tests (``backend/tests/test_jsonb_normalizers.py``):

- 10 new tests added (parametrized over canonical pass-through, empty
  dict, None, list/string/int wrong-types; idempotency tests for
  both helpers; schema-version constant sanity).
- Existing 744 normaliser tests unchanged; all 754 collect + run.

Validation:

- ORM smoke: ``from app.models.firmware import Firmware`` resolves all
  5 new column names against ``Firmware.__table__.columns`` ✓
- Normaliser smoke: idempotency, None pass-through, defensive coercion
  on wrong type — all verified inline before commit.
- Pytest: 10 / 10 windows_info_walk_result tests pass under
  uv-managed pytest 9.0.3 / Python 3.14 ✓
- Ruff clean across all 4 touched files.

The alembic ``upgrade head`` round-trip happens at the end of the
λ.α.D stream (Rule #8 backend+worker+migrator rebuild), not per-piece
— per Pattern P5 + Rule #25 (one rebuild amortizes across all commits
in the slice).

Next slice: ``windows_info_walker.py`` Rule #39 triplet wiring
``vol3_runner.run_vol3_plugin(...,'windows.info')`` against
``memory_dump_image`` rows + register in ``walker_registry.py``.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eastmadc added a commit that referenced this pull request May 22, 2026
…ibution

Adds `bt_fw_banner` format + parser that reads the first 4 KB + last 8 KB
of any BT firmware blob and identifies vendor + chipset + version from
CONTENT, not filename. Makes the BTFM→Broadcom misattribution class
(postmortem 2026-05-15) impossible by construction.

Supports three families:
  * QCA Atheros Rome / WCN3xx0 / FastConnect — parses BTFM.<3-letter-
    codename>.x.y.z-<build>-QCA*ROM[Z]?-N banners + Patch Release
    PF=<chip>ROM= lines. Codenames CMC/CHE/APA/HAS/MOS map to
    WCN3950/3990/3988/QCA6390/WCN6750 per upstream btqca.c.
  * Broadcom / Cypress / Infineon HCD — HCI command-stream walker
    validates WRITE_RAM + LAUNCH_RAM terminator, extracts chip ID
    from in-payload BRCMcfgS/BRCMcfgD block. CYW prefix → cypress.
  * MediaTek WMT / btmtk — 32-byte btmtk_patch_header struct (per
    btmtk.c) + BT-vs-WiFi disambiguation via WMT/BT_FW/btmtk markers.

Tier 0 BRAKTOOTH (CVE-2021-28139 cluster) pin fires when the banner
confirms WCN3950 / WCN3990 / WCN3998 — direct content evidence of a
chipset that Qualcomm marked patches "TBA" per the 2021 ASSET
disclosure. Higher confidence than the curated YAML soft-chipset match.

ParsedBlob gains a `vendor: str | None` field; detector.py uses it to
override Classification.vendor when populated (content > filename per
Rule #19 + the BTFM correction postmortem). Existing parsers leave it
None and inherit classifier-derived vendor unchanged.

YAML wiring: BTFM patterns + new FastConnect family prefixes
(htbtfw/msbtfw/hpbtfw/hmtbtfw/wcnhpbtfw) + BCM/CYW .hcd + MediaTek
mt7xxx/mt66xx_bt_/romv*_be_patch_ + NV calibration all route to
bt_fw_banner. NV files correctly return family="unknown" (no banner
present) and inherit filename attribution.

Tests: 23 new in test_bt_firmware_banner_parser.py (every codename,
TLV header, HCI walker including truncation reject, MediaTek gates,
negative cases). Updated 12 stale BTFM=broadcom assertions in
test_hardware_firmware_classifier_patterns.py to expect qualcomm
(these were authored before yesterday's 3d8d018 correction).

Live-canary on G32 BTFM corpus: 6/6 .tlv/.ver files now report
vendor=qualcomm + version=banner + chipset_target from content; both
NV .bin files correctly return unknown family.

Refs:
  * postmortem-btfm-correction-and-corpus-2026-05-15.md (rec #1)
  * postmortem-hw-firmware-adaptive-session-2026-05-15.md (rec #1)
  * Linux upstream btqca.c / btqca.h / btmtk.c / btbcm.c
  * Scout research notes 2026-05-16 (this campaign)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eastmadc added a commit that referenced this pull request May 22, 2026
End-of-session postmortem + patterns + antipatterns for the BT firmware
banner parser campaign. Ships yesterday's recs #1-#4 in 4 commits
(c3a8fb2 / 88082f0 / d585c79 / ae91e98); multi-persona Citadel review
caught CVE-2021-28139 ESP32-only attribution before rebuild captured
it as a fresh false-positive class (~18 RCE-CVSS-8.8 rows per
QCA-Rome firmware).

Final corpus verification: 21 Tier 0 BRAKTOOTH pins on G32 + 18 on G30
(3 legit DoS CVEs each), MediaTek BT detection works on DPCS10
ROMv4_be_patch files, wpa_supplicant + libbluetooth.so paths classify
correctly under new `aosp` vendor, spec-level KNOB/BLUFFS/BIAS/BLUR
advisories fire on every vendor's BT blobs via vendor_regex.

Patterns extracted (8): content-evidence parser as architectural
countermeasure; parallel research scouts before spec work; live-canary
on real corpus during development; multi-persona Citadel review;
reviewer fixup commit stays bisect-clean; end-of-session verification
on corpus; lazy I/O in per-blob parsers; filename↔content mismatch
as forensic metadata.

Antipatterns extracted (8): disclosure-batch attribution without
per-CVE evidence (the campaign's headline catch); hardcoded scan
window mismatched real banner location; test fixture defaults bypass
negative cases; parallel rebuild + reviewer fixup on stale image;
vendor-fork mirror duplicates AOSP attribution without divergence;
family-name chipset approximation; codename docstring generation
conflation; ASCII-printability gates accept binary padding.

Cross-cutting themes:
* "Source-citation laziness" generalises across yesterday's #1/#8 + today's #1/#6/#7
* Reviewer-mode external enforcement of Rule #19 evidence-first
* Rule #25 per-piece commits robust under reviewer-driven correction pressure

Refs:
  * Yesterday's unified postmortem: postmortem-hw-firmware-adaptive-session-2026-05-15.md
  * Yesterday's recs queue: 8 items, this session shipped #1-#4
  * Next-session candidates: Reviewer C H1 (YAML codename externalization, ~1hr)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eastmadc added a commit that referenced this pull request May 22, 2026
Recommendation #3 from postmortem-bt-banner-parser-session-2026-05-16.md.
Documents all 5 YAML extension surfaces for operator-extensible firmware
detection + CVE attribution:

1. vendor_prefixes.yaml — canonical vendor names + aliases
2. firmware_patterns.yaml — filename patterns + path_contexts refinement
3. bt_qca_codenames.yaml — QCA codename map + BrakTooth scope + MTK chips (H1)
4. bt_banner_cve_pins.yaml — banner-pin → CVE rule engine (H2)
5. known_firmware.yaml — curated CVE matcher with vendor_regex (2026-05-16)

Covers:
- Architecture recap (classifier → parser → CVE matching pipeline) with
  the content-evidence > filename-evidence rule baked in via
  ParsedBlob.vendor override contract.
- Every field in every YAML file (required vs optional, types, defaults).
- The Format → Parser mapping table with all 10 in-tree parsers.
- Path-context priority handling + Reviewer A M5 deterministic-tiebreaker
  semantics.
- Reviewer B 2026-05-16 NVD-CPE-per-CVE verification discipline + the
  CVE-2021-28139 canary that protects against regression.
- Graceful-degrade behavior table per file (all-or-nothing for H1+H2;
  per-entry skip for classifier YAMLs).
- End-to-end worked example: adding coverage for a hypothetical new QCA
  Hennessy / QCA6490 codename — every file that needs editing, the one
  parser-code change for the filename-prefix map, the Rule #8 rebuild,
  and the SQL verification queries.
- Code pointers + cross-references to the Reviewer B postmortems +
  CLAUDE.md Rules #19 and #34.

Renders cleanly with the existing docs/features/*.md style.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eastmadc added a commit that referenced this pull request May 22, 2026
Applies findings from the 3-reviewer Citadel review (arch + forensic +
adaptability) against the 4 feature commits c7a6106..5f40eb2 in this
session.

Reviewer A (architecture):

  A1-HIGH: MtimeCachedYamlLoader belonged in app/utils/, not in
  hardware_firmware/. The class is generic over T and has zero
  hw-firmware semantics — keeping it under hardware_firmware/ signals
  wrong scope to future authors AND forces cross-subpackage imports
  from cve_matcher.py. Moved to app/utils/yaml_cache.py (mirrors the
  sandbox.py / truncation.py / pagination.py siblings). Updated 3
  importers (patterns_loader.py, cve_matcher.py, test_yaml_hot_reload.py)
  + 3 caplog logger references. Renames cleanly under git mv.

  B1-HIGH: firmware_service.py:761 was overwriting device_metadata
  instead of merging. Pre-existing bug — the e2f8333 commit's new
  extraction_diagnostics["nested_extract"] sub-key made the bug
  reachable on the upload happy path (was previously only triggered
  on extraction failures). Mirrors the proven merge-then-stamp
  pattern at firmware_paths.py:787-791: load existing via
  _normalize_firmware_device_metadata, dict-copy, set the new key,
  stamp. Preserves any prior keys (detection_roots etc) the upstream
  callers may have written.

  B4-MEDIUM: _is_archive_dense_layout's min_archive_size_bytes
  default lowered from 10 MB → 1 MB. The 10 MB floor was biased
  toward Tegra/Samsung-scale packages and ruled out small-vendor
  embedded firmware (ESP32 packages typically 4-8 MB, Nordic
  SoftDevice updates ~1.5 MB). 1 MB still suppresses the stray-tarball-
  in-a-config-dir false-fire while opening the gate for the broader
  IoT/embedded corpus the user signaled wairz must adaptively serve.

Reviewer C (adaptability):

  REC-1-HIGH: Subdirectory probing added to _is_archive_dense_layout.
  Previously the gate only inspected the top level — a vendor wrapping
  archives in payloads/ / firmware/ / images/ subdirs would slip
  through. Added _probe_subdirs_for_archive_density(): when top
  level has zero files AND ≤8 subdirs, probes each at depth-1 with
  the same density test. Bounded by the subdir count cap so
  adversarial inputs can't blow up the probe. Adaptability win: any
  external uploader's subdir-wrapping convention now triggers
  recursion without hard-coded vendor subdir names.

  CC-1-HIGH: Vendor proactive seed expanded from 4 → 28 vendors in
  the _VendorTable defaults. Allwinner / Rockchip / Marvell /
  Espressif / Lattice / Xilinx / Renesas / STMicro / Nordic /
  Microchip / Infineon / TI / etc. — each is already referenced in
  firmware_patterns.yaml OR is a likely operator-upload target.
  Display strings only, zero behaviour change. Eliminates the
  "vendor=allwinner → display='Allwinner'" title-cased fallback for
  the 24 most-common chip vendors operators will surface.

Tests: 344/344 hw-firmware regression suite still passes.

Deferred to follow-ups (documented in postmortem):
  A2-MED: Dual .get() + __call__ surface (transition cost — keep
    until existing fixtures fully migrated)
  A3-MED: sys.modules[__name__] resolver pattern (refactor to
    explicit DI in a future Rule #27 N+1 split)
  A4-LOW: patterns_loader.py size approaching Rule #28 threshold
    (1437 LOC — defer until 1500+)
  B2-MED: nested_extract sub-key normaliser (Rule #19: defer until
    ≥3 consumers — currently only firmware_service.py writes it)
  C1-MED: Tegra content-evidence parser (~300 LOC, defer to
    dedicated commit)
  C2-LOW: Tegra CVE pins in known_firmware.yaml (defer pending
    Reviewer B per-NVD-CPE verification — antipattern-prevention
    discipline from 2026-05-15..17 sessions)
  D1-MED: Realtek confidence-ladder ambiguity (added inline comment
    on the truth table)
  D2-MED: Realtek tests target private API (deferred — would require
    35+ test restructuring)
  REC-2-MED: .7z / .tar.zst / .deb suffix support (requires apt
    deps + Dockerfile change — separate commit)
  HOT-1+CC-3-MED: list_extension_points MCP tool + UI signal for
    "did my YAML take effect" (~90 LOC; planned follow-on commit)
  RTL-1-MED: tighten soft-fallback regex placement bound (next
    session; small false-positive surface today)
  CC-2-MED: extracted_via_shortcut binary → 3-state literal
    (refactor; preserves backward compat in this fix commit)
  CC-4-MED: conftest.py loader_with_tmp_yaml fixture helper (defer)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eastmadc added a commit that referenced this pull request May 22, 2026
Applies Reviewer B's CRITICAL findings from the multi-persona forensic
review against the 4 feature commits (c7a6106..5f40eb2) + the prior
reviewer-fix (7730915).

F-FORENSIC-10 CRITICAL — bt_banner_cve_pins.yaml schema gate
============================================================

Before this commit, a pin with ONLY `family: <X>` set (no chipset /
codename / banner / version narrowing) passed validation. A future
operator writing:

    pins:
      - id: realtek-ble-cve
        family: realtek_bt
        cves: [CVE-2024-48290, ...]

…would fire the RTL8762E SDK CVEs against ALL 17 chipsets in
bt_realtek_project_ids.yaml. Per NVD CPE, CVE-2024-48290 / CVE-2025-44526
/ -44531 / -44559 are RTL8762E-SDK-specific — applying them to
RTL8761B / RTL8852A / etc would replicate the BTFM/BrakTooth
disclosure-batch antipattern this codebase has hit 3 times now
(2026-05-15: BTFM→Broadcom, 2026-05-16: CVE-2021-28139→Qualcomm Rome,
2026-05-17: CVE-2021-34147/31609/31612→Qualcomm Rome).

Fix: `_parse_banner_cve_pin` now REJECTS pins where `family:` is
set AND no other narrowing condition is present. The error message
explains the antipattern + cites Reviewer B 2026-05-18. Loud rejection
at YAML load time + the keep-previous-state contract means a bad pin
falls back to the prior valid YAML — operator iterates without losing
production CVE attribution.

Defense-in-depth: this is a SCHEMA gate that fires at YAML load time.
The runtime gate (curated_yaml tier in cve_matcher.py) still does
per-CVE-shape vendor/category/chipset_regex matching, so the bug
class is now blocked at TWO layers: at-load (schema) + at-match
(matcher fields).

F-FORENSIC-11 HIGH — curated-tier confidence floor
=================================================

Before: a LOW-confidence blob (Realtek BT parser's soft-fallback path
emitting `vendor=realtek, confidence=low` from any `[Rr]ealte[ck]`
ASCII pattern in a head window) would trigger curated YAML CVE
attribution under `vendor: realtek` entries. A kernel module or
Android image containing "Realtek Inc." in a string table would be
attributed Realtek BT CVEs despite carrying no BLE codepath.

Fix: `_match_curated` now skips blobs with
`detection_confidence == "low"` — DEBUG-logged for audit but produces
zero curated-tier rows. The chipset_soft semantic (separate
mechanism) is unaffected — it downgrades the MATCH confidence on
the curated row, not the blob's detection_confidence.

The two gates are complementary:
- F-FORENSIC-11 gates on BLOB EVIDENCE quality (parser-derived)
- F-FORENSIC-10 gates on PIN AUTHOR-INTENT quality (schema-enforced)

Tests added (per Rule #46 paired-canary discipline):
- `test_family_only_pin_rejected_per_forensic_invariant` — synthesises
  the family-only antipattern + verifies the gate rejects + the
  loader keeps the prior valid state (the BRAKTOOTH default pin)
- `test_family_paired_with_chipset_in_accepted` — Rule #46 negative
  canary: the correct shape (family + chipset_target_in) IS accepted
- `test_match_curated_skips_low_confidence_blob` — vendor=realtek +
  confidence=low + a matching curated entry → ZERO rows
- `test_match_curated_fires_on_medium_confidence_blob` — Rule #46
  negative canary: medium-confidence blob STILL triggers curated tier
  (proves the gate doesn't over-skip)

Updated 2 pre-existing tests (test_bt_banner_cve_pins_loader.py
test_multiple_pins_load_in_yaml_order + test_yaml_hot_reload.py
test_bt_banner_cve_pins_yaml_hot_reload) — added `chipset_target_in:
[...]` narrowing to the synthetic fixtures so they comply with the
new schema invariant.

All 348 hw-firmware tests pass (was 344 pre-fix + 4 new).

Reviewer B findings NOT applied in this commit (deferred per Rule #19
and the postmortem's "Recommendations Carried Forward" queue):
  F-FORENSIC-03 (Tegra per-CVE NVD-CPE pin map): no Tegra CVE pins
    being shipped this session — documented for future curated entry
    authors with the explicit per-CVE chipset/version narrowing recipe
  F-FORENSIC-01 (hot-reload mid-scan): snapshot loaders at top of
    match_firmware_cves — deferred (defends a structural invariant
    operators won't typically hit; ~5 LOC follow-up)
  F-FORENSIC-04 (TOS Trusty/ATF/NVIDIA-wrapper provenance): content-
    evidence parser needed; defer to dedicated Tegra parser commit
  F-FORENSIC-06/07 (category=dtb / mcu downstream risk): no current
    code path triggers; documented in postmortem
  F-FORENSIC-08 (`^.+\.bup$` over-broad): defer — DB query confirmed
    zero collision in current corpus
  F-FORENSIC-13 (Realtek wifi→bluetooth flip): zero blobs affected
    in live corpus (DB-verified)
  F-FORENSIC-15 (DS1 zero curated CVE rows initially): operator
    expectation documented in postmortem

Critical Scout A correction (re-verified by Reviewer B via NVD):
DS1 firmware is L4T R32.3.1 — the FIRST FIXED version of CVE-2019-5680
(Selfblow). Scout A's report incorrectly conflated R32.3.1 with the
JetPack 4.3 R32.3 base release. Per NVD, CVE-2019-5680's CPE list
caps at R32.2, so R32.3.1 is NOT vulnerable. Future Tegra CVE pins
MUST exclude CVE-2019-5680 for R32.3.1+ targets.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eastmadc added a commit that referenced this pull request May 22, 2026
…05-18

Extracts patterns + anti-patterns from the 2026-05-18 session.

Knowledge files:
- .planning/knowledge/hw-firmware-adaptive-session-2026-05-18-patterns.md
  (10 successful patterns + 9 key decisions; pre-implementation parallel
  scouts, multi-persona reviewer dispatch, bytes-weighted adaptability
  gate, confidence ladder, YAML hot-reload keep-previous-on-malformed,
  schema gates against disclosure-batch antipatterns, generic-primitive
  module location, recursive Rule #19 evidence-first discipline)
- .planning/knowledge/hw-firmware-adaptive-session-2026-05-18-antipatterns.md
  (10 failed patterns + 8 cross-cutting themes; prompt-claim acceptance
  without source verification, JSONB write-then-overwrite, filename-only
  attribution, threshold-tuning without cross-corpus measurement,
  top-level-only scan, family-only CVE pin schema gap, low-confidence
  curated-tier pollution, Scout-report acceptance without per-CVE NVD)

Quality rule candidates appended to .claude/harness.json (4 new, 63 total):
- auto-hw-firmware-adaptive-2026-05-18-device-metadata-overwrite
  (catches `firmware.device_metadata = _stamp_*({...})` pattern that
  clobbers prior JSONB keys)
- auto-hw-firmware-adaptive-2026-05-18-realtek-offset-8-project-id
  (catches re-introduction of the offset-8 project_id misread)
- auto-hw-firmware-adaptive-2026-05-18-yaml-cache-hw-firmware-import
  (catches imports of the old hardware_firmware._yaml_cache path
  post-A1 migration)
- auto-hw-firmware-adaptive-2026-05-18-low-confidence-curated-tier
  (catches accidental removal of the F-FORENSIC-11 confidence floor)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eastmadc added a commit that referenced this pull request May 22, 2026
Closes Reviewer C CC-3 / HOT-1 / HOT-2 from postmortem
hw-firmware-adaptive-session-2026-05-18 in a single MCP tool: now
operators can discover the extension surfaces and verify their YAML
edits without shelling into the container.

What the tool returns
---------------------
JSON payload with three sections:

(1) extension_surfaces[] — one entry per loader registered via
    yaml_cache.register_loader(): surface_name, path, loaded_from_
    yaml (bool), yaml_mtime_iso, summary (operator-friendly entry
    count), reload_count, last_warning (the str | None field added
    in 63e3bf5), status ("loaded" / "defaults" / "malformed_fallback").

(2) parser_format_map — {format_string: parser_class_name} walked
    from PARSER_REGISTRY at call time. A new parser self-registering
    via parsers/base.register_parser() surfaces here without any
    tool change.

(3) bt_parser_families — verbatim from a new public
    BT_PARSER_FAMILIES tuple in parsers/bt_firmware_banner.py.
    Currently 4 entries (qca_rome / broadcom_hcd / mediatek_bt /
    realtek_bt).

Optional input.surface_filter is a case-insensitive regex narrowing
the returned surfaces (e.g. "^bt_" for BT-only).

Loader registrations
--------------------
7 register_loader() call sites added at module-load time:
  patterns_loader.py — vendor_prefixes, firmware_patterns,
    firmware_patterns_contexts, bt_qca_codenames, bt_banner_cve_pins,
    bt_realtek_project_ids (6)
  cve_matcher.py — known_firmware (1)

Each is a one-line call after the loader instantiation. Adding a 7th
or 8th YAML surface in the future means: instantiate the loader +
register_loader("<surface>", _LOADER). Zero changes to the MCP tool.

Tests (5 new in test_hardware_firmware_mcp_tools.py)
---------------------------------------------------
- test_list_extension_points_returns_registered_yamls
  (all 7 expected surfaces appear + each has required shape)
- test_list_extension_points_excludes_unregistered_loader
  (Rule #46 negative canary — registry isn't auto-discovering)
- test_list_extension_points_surface_filter_narrows_results
- test_list_extension_points_surface_filter_invalid_regex_returns_error
- test_list_extension_points_surfaces_last_warning_after_malformed_yaml
  (end-to-end canary: malformed YAML → non-null last_warning visible
  via MCP tool output, status=malformed_fallback)

168/168 tests pass across yaml_hot_reload + mcp_tools +
classifier_patterns + cve_matcher. No regressions.

Refs:
- Postmortem hw-firmware-adaptive-session-2026-05-18 Rec #1
- CLAUDE.md Rule #19 (evidence-first — last_warning surfaces the
  WHY of silent-fallback states to operators)
- CLAUDE.md Rule #25 (per-piece commits — foundation 63e3bf5 first,
  tool here)
- CLAUDE.md Rule #46 (paired-canary discipline)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eastmadc added a commit that referenced this pull request May 22, 2026
Closes Reviewer A C1 + Reviewer C TEG-1 deferred from postmortem
hw-firmware-adaptive-session-2026-05-18. Adds a content-evidence
counterweight to the 24 filename-only Tegra patterns shipped
2026-05-18 (commit 3000a9e): operator-renamed Tegra blobs whose
filenames don't match any in-tree pattern still classify as
vendor=nvidia when content evidence (ELF section names / FDT
compatibles / Android boot.img cmdline / Debian ar magic) confirms.

In-scope formats (4 of 6 from the user prompt)
==============================================

1. ELF (\x7fELF) — bpmp/spe/adsp/cboot kernel-mode binaries.
   Byte-scan for Tegra-specific section names (.bpmp_fw / .spe_fw /
   .adsp_fw / .tegra_cboot), symbol prefixes (T18x_/T19x_/T21x_/
   T23x_/tegra_/bpmp_), or .rodata SOC strings (nvidia,tegra186 /
   194/210/234 / NVIDIA Tegra / NVIDIA Jetson). HIGH on canonical
   evidence; MEDIUM on only-rodata match (operator stripped sections).

2. FDT (\xd0\x0d\xfe\xed) — tegra*-*.dtb. Byte-scan for
   nvidia,tegra* compatible + Jetson model strings. HIGH confidence.
   Ref: Devicetree Specification v0.4 §5.2; libfdt FDT_MAGIC.

3. Android boot.img (ANDROID!) — ds1-*.img. MEDIUM confidence ONLY
   when cmdline / kernel preamble carries a Tegra hint; without it
   the parser returns None (refuses to fabricate Tegra attribution
   from Android-generic magic). Ref: AOSP bootimg.h.

4. Debian ar (!<arch>\n) — nvidia-l4t-*.deb packages. vendor=debian
   on the OUTER container; inner components reclassified after
   unblob unpacks the control archive. Ref: GNU ar format.

Deferred TBDs (2 of 6)
======================

5. NVIDIA wrapper magic for tos*.img / mb1*.bin — authoritative
   bytes not pinned from public sources (NVIDIA L4T docs, OE4T
   meta-tegra, U-Boot Tegra drivers, developer forums all surveyed
   within Scout 2 dispatch budget). Filename-pattern carries until
   bytes verified from a live BSP install.

6. NVIDIA BUP container (.bup) — same TBD status as (5). Generated
   by Linux_for_Tegra/bootloader/bup_generator scripts; magic not
   pinned.

Per Rule #19 evidence-first + Rule #6 (no-guess CLI/magic flags),
both TBDs are explicit deferrals — never guess at magic bytes.
Filename-pattern carries for those subsets in the meantime.

Integration
===========

detector.py invokes parse_tegra_blob() as a CONTENT-EVIDENCE SECOND
PASS immediately after the per-format filename-stage parser, gated
on magic[:4] membership. When the parser returns non-None, the
detector merges vendor / chipset_target / metadata via
merge_tegra_evidence(). Rule #19 — content beats filename, BUT a
filename-stage parser that confidently set a competing vendor
(e.g. qualcomm) is preserved (the byte-scan can't disambiguate
e_machine cheaply on the hot path).

The Tegra parser is imported at module-level in detector.py (Rule
#40 — function-local imports must sit at the function-body top;
detector.py:21 import is the cleanest placement).

Tests (19 in backend/tests/test_tegra_blob_parser.py)
=====================================================

Per Rule #46 paired-canary discipline:
- ELF positive: section_name + symbol_prefix + rodata_soc → high
- ELF medium: only-rodata SOC token → medium confidence
- ELF negative: generic AArch64 ELF returns None
- FDT positive: nvidia,tegra194 compatible → high + t194
- FDT negative: Raspberry Pi DTB → None
- Android boot.img positive: jetson-nano cmdline → medium
- Android boot.img negative: Pixel 6 cmdline → None (refuses
  fabrication)
- Debian ar: vendor=debian / subset=deb_ar / medium
- LOAD-BEARING canary: operator-renamed Tegra ELF (foo.bin) STILL
  classifies as vendor=nvidia via content evidence
- 6 merge_tegra_evidence overlay tests (vendor precedence,
  chipset_target preservation, metadata init)
- 4 negative-magic + edge-case tests (empty, short, unreadable, random)
- Rule #46 regression canary: synthesized .bpmp_fw section name
  in an otherwise-clean ELF flips the negative test to positive,
  proving the section-name scan is actually active

82/82 tests pass across detector_sanitizers + parsers + tegra_blob.
No regressions.

Refs:
- Postmortem hw-firmware-adaptive-session-2026-05-18 Rec #2
- 2026-05-18 commit 3000a9e (24 Tegra filename patterns)
- CLAUDE.md Rule #19 (evidence-first — magic bytes never guessed)
- CLAUDE.md Rule #25 (per-piece commits)
- CLAUDE.md Rule #34 (graceful-degrade — parser returns None
  on any internal error)
- CLAUDE.md Rule #40 (function-local imports at function-body top
  — detector import lifted to module level)
- CLAUDE.md Rule #46 (paired-canary discipline)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eastmadc added a commit that referenced this pull request May 22, 2026
Closes Reviewer A C2 + Reviewer B F-FORENSIC-03 deferred from
postmortem hw-firmware-adaptive-session-2026-05-18 Rec #3. 6 new
curated CVE family entries covering the NVIDIA Tegra/L4T BSP cluster
that DS1 (project d360f8f5) and other Jetson-based firmware images
depend on. Per-CVE NVD CPE list verified via direct WebFetch on
services.nvd.nist.gov/rest/json/cves/2.0?cveId=<CVE> recursively for
EACH of the 6 CVEs — Scout report's NVD claims independently
re-fetched before commit.

Recursive-verification discipline (Reviewer B 2026-05-15..18 caught
CVE-attribution failure modes 4 sessions in a row): every CVE-
attribution claim — whether from user prompt, scout report, or
reviewer finding — gets the direct NVD URL fetch before pinning.
The 6 fetches surfaced 3 user-prompt-discrepancies that NVD
overruled:

  * CVE-2021-1111 — user said "ALL Jetsons"; NVD CPE EXCLUDES
    TX1/Nano (only AGX-Xavier+TX2+TX2-NX+Xavier-NX listed).
    chipset_regex narrowed accordingly.

  * CVE-2021-34372 — user said product=tegra_tos_trusty; NVD CPE
    uses product=jetson_linux. wairz curated families: schema has
    no `product` field (only banner_cve_pin schema does); we narrow
    via vendor=nvidia + category=tee, which is the schematic
    equivalent for the Trusty OTE attack surface.

  * CVE-2022-42269 — user said "AGX-Xavier/TX2/Xavier-family"; NVD
    CPE ALSO includes jetson_tx1. chipset_regex expanded to include
    T210/TX1 (Nano stays excluded — different hardware anchor).

NVD wins per Rule #19 evidence-first in all 3 cases. All 6 pins
satisfy F-FORENSIC-10 narrowing (chipset_regex AND/OR version_regex
present — no family-only attribution).

Per-CVE summary
===============

| CVE | Fix at | Scope | Discrepancy? |
|-----|--------|-------|--------------|
| CVE-2019-5680 | R32.2 | TX1 only | None (R32.2 IS fix) |
| CVE-2021-1111 | R32.6.1 | AGX-Xav+TX2+TX2-NX+Xav-NX | NVD excludes TX1+Nano |
| CVE-2021-34372 | R32.5.1 | ALL Jetsons (TEE) | product=jetson_linux not tegra_tos_trusty |
| CVE-2021-34397 | R32.5.1 | TX2+Xavier family | None |
| CVE-2022-42269 | R32.7.2 | AGX-Xav+TX2+Xav-NX+TX1 | NVD adds TX1 |
| CVE-2022-42270 | R32.7.2 | Xavier only (NVDLA) | None |

Forward-prepared note
=====================

version_regex requires the L4T BSP release string ("R32.x.y" style)
to appear in blob.version OR any blob metadata value. The current
Tegra parser (commit 8054d22) does NOT yet extract L4T release from
blob content — these pins will fire when a future enhancement adds
L4T release extraction (e.g. parse /etc/nv_tegra_release on the
firmware tree → populate firmware.device_metadata["l4t_release"],
OR scan Tegra-blob head for "R<N> (release), REVISION: <x.y>"
banner string and store in blob.metadata).

Strict version_regex is the right discipline NOW per Reviewer B
discipline — better forward-prepared with zero false-positives than
firing on every Tegra blob regardless of L4T version.

Out-of-scope (explicit per user direction)
==========================================

CVE-2021-34373..34396 from the same NVIDIA security bulletin
disclosure batch — DO NOT batch-extrapolate. Each future CVE needs
its own NVD WebFetch verification before pinning. The disclosure-
batch antipattern has bitten wairz 4 sessions in a row (BTFM
2026-05-15, CVE-2021-28139 2026-05-16, CVE-2021-34147/31609/31612
2026-05-17, CVE-2019-5680 Selfblow 2026-05-18); the per-NVD-CPE
recipe applies recursively for any future Tegra coverage extension.

Tests (10 new in test_hardware_firmware_cve_matcher.py)
=======================================================

- test_tegra_cve_pins_all_six_loaded — all 6 entries present
- test_tegra_cve_pins_satisfy_f_forensic_10_narrowing —
  chipset_regex or version_regex on every pin (no family-only)
- test_cve_2019_5680_chipset_regex_tx1_only — accepts TX1,
  rejects TX2/Xavier/Nano (canonical Selfblow scope)
- test_cve_2021_1111_chipset_regex_excludes_tx1_and_nano —
  Rule #46 paired canary for the user-prompt discrepancy
- test_cve_2022_42269_chipset_regex_includes_tx1 —
  Rule #46 paired canary for the TX1-inclusion discrepancy
- test_cve_2022_42270_xavier_only_excludes_tx2 — NVDLA Xavier-only
- test_cve_2021_34397_excludes_tx1_and_nano — TX2/Xavier family
- test_cve_2021_34372_has_no_chipset_regex_per_nvd_all_jetsons —
  confirms intentional chipset_regex absence (ALL-Jetsons scope)
- test_tegra_version_regex_matches_pre_fix_l4t_releases —
  forward-prepared canary that pre-fix L4T release strings WILL
  match when extraction lands
- test_tegra_cve_pins_carry_nvd_url_reference — verifiability
  discipline: each pin's notes cites the NVD URL

66/66 cve_matcher tests pass. No regressions.

Refs:
- Postmortem hw-firmware-adaptive-session-2026-05-18 Rec #3
- NVD CPE WebFetch for each CVE (see notes field URLs)
- CLAUDE.md Rule #19 (evidence-first — NVD CPE list IS truth)
- CLAUDE.md Rule #25 (per-piece commits)
- CLAUDE.md Rule #46 (paired-canary discipline)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eastmadc added a commit that referenced this pull request May 22, 2026
Reviewer B (forensic-domain persona, post-implementation review of
session-2026-05-15 commits 63e3bf5..6bc1c1d) caught 2 CVSS-value
drifts in the Tegra CVE pins. Recursive verification via independent
NVD WebFetch on each CVE confirmed:

  * CVE-2021-1111 — shipped cvss_score=6.0; NVD primary (NVIDIA CNA
    CVSS 3.1) = 6.7 MEDIUM (AV:P/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:H).
    Off by 0.7. Updated to 6.7.

  * CVE-2021-34397 — shipped severity=medium / cvss_score=5.5; NVD
    primary (NIST CVSS 3.1) = LOW / 2.3 (AV:L/AC:L/PR:H/UI:N/S:U/
    C:N/I:N/A:L). Off by 3.2 points + 1 severity tier (overrated).
    NVIDIA CNA secondary = 1.9 LOW (confirms low severity).
    Updated to severity=low / cvss_score=2.3.

The shipped values were Scout-3-derived without independent NVD-
primary verification of the CVSS field — the recursive-verification
discipline (Reviewer B 2026-05-15..18) caught it post-implementation.
NVD primary is the authoritative source for both CVE attribution
AND CVSS grading per Rule #19 evidence-first.

No CRITICAL findings in the recursive verification — all 6 pins'
CHIPSET / VERSION scopes match NVD CPE list as shipped (Reviewer B
independently re-verified the 3 user-prompt-discrepancies caught
in commit 6bc1c1d). Only the 2 CVSS fields drifted.

Tests
=====
Added test_tegra_cve_pins_cvss_scores_match_nvd_primary —
regression canary that fails fast if any future edit drifts CVSS
values away from NVD primary without re-verification. The expected
table is the NVD primary CVSS 3.1 base score per CVE (NVIDIA CNA
or NIST whichever is primary per NVD page).

Refs:
- Reviewer B forensic review findings B2 + B3 (2026-05-15)
- https://nvd.nist.gov/vuln/detail/CVE-2021-1111 (CVSS 3.1 = 6.7)
- https://nvd.nist.gov/vuln/detail/CVE-2021-34397 (CVSS 3.1 = 2.3)
- CLAUDE.md Rule #19 (NVD CPE list IS truth — extends to CVSS too)
- CLAUDE.md Rule #25 (per-piece commits — this is the forensic-fix
  slice; schema gate analog ships separately)
- CLAUDE.md Rule #46 (paired-canary discipline)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eastmadc added a commit that referenced this pull request May 22, 2026
Reviewer A's architecture review (post-implementation of session-
2026-05-15 commits 63e3bf5..6bc1c1d) caught a 5th failure path
missed in the initial last_warning implementation: when a
previously-loaded YAML vanishes from disk (operator deletes /
renames / moves the file mid-edit), the loader's _handle_missing
keeps the previous valid state + logs WARN but does NOT populate
last_warning.

Symptom this fix prevents
=========================
The list_extension_points MCP tool reads loader.last_warning to
report load state. Without this fix:
  - vanished YAML → loader keeps previous state (correct behavior)
  - WARN log fires (operator-invisible without shell access)
  - last_warning stays None
  - MCP tool reports status="loaded" / last_warning=null — exactly
    contradicting HOT-2's "operators see WHY their state silently
    fell back" goal.

The fix sets last_warning = "file vanished after successful load:
<path>" inside _handle_missing when _loaded_from_yaml=True. The
warning clears on a subsequent successful reload (existing path
at line 274 already does this).

Tests
=====
- test_last_warning_populated_when_file_vanishes_after_successful_load
  (Rule #46 canary — pairs with the existing
  test_file_vanish_after_successful_load_keeps_previous_state which
  only asserted state preservation)
- test_last_warning_cleared_when_vanished_file_is_restored
  (operator restoration path)

3/3 vanish tests pass (existing + 2 new).

Refs:
- Reviewer A A1 finding (2026-05-15)
- Postmortem hw-firmware-adaptive-session-2026-05-18 (deferred
  HOT-2 surface; this commit completes the operator-visibility
  contract for the 5th failure path)
- CLAUDE.md Rule #19 (evidence-first surfaces all failure modes
  to operators)
- CLAUDE.md Rule #25 (per-piece commits)
- CLAUDE.md Rule #46 (paired-canary discipline)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eastmadc added a commit that referenced this pull request May 22, 2026
… + 16-entry pre-narrowing

Adds the F-FORENSIC-10 invariant analog at the curated CVE tier
(cve_matcher._parse_known_firmware_data). Reviewer B B1 deferred from
postmortem 2026-05-15. Mirrors the BT YAML layer's family-only rejection
in patterns_loader._parse_banner_cve_pin (commit 51db3c8 2026-05-18).

GATE SHAPE (matches user-prompt + Reviewer B 2026-05-18 invariant):
  - CVE-bearing entry MUST set at least one of {chipset_regex,
    category_regex, version_regex, vendor_regex} beyond base
    vendor + category exact match.
  - Failed entries are SKIPPED + WARN-logged with all 4 narrowing
    field names so operators see exactly what to add.
  - Advisory-only entries (cves: [] or missing) bypass the gate.
  - Hard-coded allowlist tuple _KNOWN_FIRMWARE_NARROWING_FIELDS for
    cross-stack alignment with the BT layer's invariant.

PRE-NARROWING BEFORE GATE ACTIVATION (per Rule #19 evidence-first +
Rule #31 width-canary): a corpus audit revealed 16 currently-firing
entries (5,000+ CVE rows across G32+G30+DPCS10×3+DS1) that would have
been silently dropped by the gate. Each pre-narrowed before activation:

  CVE-2017-18159 (×2 entries, Qualcomm EDL leaked programmers):
    chipset_regex matching Snapdragon family per NVD CPE description
    "Android for MSM, QRD Android, Firefox OS for MSM" (MSM = Snapdragon
    family). Independently re-fetched NVD CPE per Rule #19 recursive
    discipline (12th NVD WebFetch this session). strict_chipset: false
    preserves soft-fallback for blobs with NULL chipset_target (typical
    for Qualcomm bootloaders pre-2026-05-15 detection improvements).

  14 other entries (FragAttacks / MediaTek modem CDMA/5G/DoS / MediaTek
  DA OOB / 5 AOSP Bluedroid / 4 AOSP wpa_supplicant): minimum-impact
  category_regex matching existing exact-match category. Preserves all
  matching semantics + satisfies the gate. Future enhancement: per-NVD
  chipset_regex / version_regex per recursive verification discipline
  (queued as carry-forward work).

Pre-narrowing audit confirmed via direct corpus SQL query:
  SELECT cve_id, COUNT(*) FROM sbom_vulnerabilities WHERE cve_id IN (...)
Returned 22 of 25 audited CVEs currently firing (CVE-2017-18159 = 144
blob rows × 5 firmwares; FragAttacks 24586/87/88 = 1176 rows × 4
firmwares each; etc.). All preserved by the pre-narrowing.

Tests: 5 new (Rule #46 paired-canary suite for the gate):
  - test_f_forensic_10_gate_rejects_family_only_cve_entry: SYNTHESIZED
    VIOLATION canary — bad entry rejected + WARN logged
  - test_f_forensic_10_gate_accepts_each_narrowing_field: each of 4
    qualified narrowing fields individually satisfies the gate
  - test_f_forensic_10_gate_canary_synthesized_violation_actually_fires:
    Rule #46 META-CANARY — WARN message contains all 4 field names
    (operator-actionable; catches refactor-flip-of-conditional regressions)
  - test_no_currently_loaded_yaml_entry_is_rejected_by_gate: regression
    canary against future YAML edits re-introducing disclosure-batch shape
  - test_cve_2017_18159_chipset_regex_matches_snapdragon_family: NVD-CPE
    derived narrowing scope (positive Snapdragon + negative non-Qualcomm)

Closes carried-forward Recommendation #1 from postmortem 2026-05-15.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eastmadc added a commit that referenced this pull request May 22, 2026
…E pins on DS1-class corpus

Activation gap discovered during final verification: the L4T release
banner extraction shipped commit f54d415 reads the blob's HEAD BYTES
for ``# R32 (release), REVISION: 3.1, ...`` strings. End-to-end test
on DS1 (firmware 295eaf7a) confirmed:

  - 99 blobs detected, 89 vendor=nvidia (44 Tegra-FDT high-confidence)
  - 0 blobs have metadata['l4t_release'] populated post-detection

ROOT CAUSE: DS1's blobs are standalone Jetson bootloader / DTB / MCU /
TEE images extracted from ``L4T_BSP_SecureBoot.R32.3.1.tar.gz``. None
of these carry the /etc/nv_tegra_release banner inline — that file
lives only in the BSP rootfs (and DS1's data.img is raw_bin, not
unblob-unpacked). However, the L4T release IS encoded in the EXTRACTION
PATH: ``L4T_BSP_SecureBoot.R32.3.1.tar.gz_extracted/bootloader/bpmp_t194
.bin``.

FIX: Add complementary _extract_l4t_release_from_path() fallback that
scans the blob's filesystem path for ``R<N>.<x>.<y>`` or ``R<N>.<x>``
patterns. Wires into all 3 affirmative-return parser subsets (ELF /
FDT / Android boot.img) with content-banner first, path-inference
fallback. Content banner WINS when both are present (Rule #19 evidence-
first — the banner inside the blob is more authoritative than the
archive's directory name).

REGEX SUBTLETY: word-boundary anchors (``\b``) DO NOT WORK for path-
segment matching because ``_`` IS a Python regex word character —
``\bR`` between ``_`` and ``R`` fails (both word chars). Switched to
negative lookbehind ``(?<![A-Za-z0-9])`` permitting ``_``, ``/``, ``-``,
``.`` as preceding separators. Negative lookahead ``(?!\.?\d)`` prevents
the pair form from matching when triple is present (e.g. ``R32.3`` is
NOT matched by the pair alternation when the full ``R32.3.1`` is
available — triple alternation wins per Python re.search ordering).

Tests: 4 new (32 total in test_tegra_blob_parser.py):
- test_l4t_release_path_inference_extracts_from_bsp_archive_dirname:
  ``L4T_BSP_SecureBoot.R32.3.1.tar.gz_extracted/bootloader/bpmp_t194.bin``
  → ``R32.3.1`` (the DS1-corpus shape)
- test_l4t_release_path_inference_handles_major_minor_only: ``R28.2``
  (older JetPack 3.2 naming, no Y-component)
- test_l4t_release_path_inference_does_not_match_arbitrary_substrings:
  Rule #46 paired canary — non-Tegra paths with ``R<N>`` substrings
  inside other words don't match
- test_l4t_release_content_banner_wins_over_path_inference: Rule #19
  evidence-first precedence canary

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eastmadc added a commit that referenced this pull request May 22, 2026
… tier

Reviewer B 2026-05-15-PM HIGH carried-forward from postmortem-hw-firmware-
tegra-activation-2026-05-15. Per Rule #19 recursive NVD-CPE
verification, the 3 SPEC-level FragAttacks CVEs (CVE-2020-24586/24587/
24588) carry ZERO Broadcom and ZERO Qualcomm CPEs in NVD — vendors
listed are ieee / linux / debian / arista / cisco / intel / microsoft
/ siemens only (no SoftMAC SoC vendor enumerated). The curated tier's
broadcom + qualcomm wcn3xxx/6xxx FragAttacks entries were over-
attributing beyond NVD direct CPE scope.

NVD-CPE verification (recursive — implementer-side WebFetch on top of
Reviewer B's independent verification):
  - CVE-2020-24586 → 5 vendors / ~26 products; 0 Broadcom; 0 Qualcomm
  - CVE-2020-24587 → 6 vendors / ~138 products; 0 Broadcom; 0 Qualcomm
  - CVE-2020-24588 → 8 vendors / ~158 products; 0 Broadcom; 0 Qualcomm

Both entries converted to advisory-only with shared advisory_id
ADVISORY-FRAGATTACK (19 chars, fits VARCHAR(20) cap):
  - broadcom entry: cves: [] + ADVISORY-FRAGATTACK; category_regex
    preserved for forensic visibility on broadcom WiFi blobs
  - qualcomm entry: advisory_id converged from ADVISORY-WLAN-FRAGATK
    → ADVISORY-FRAGATTACK; cves: [] + chipset_regex preserved on
    wcn3xxx/6xxx narrowing

Shared advisory_id means the matcher's (firmware_id, blob_id, cve_id)
UNIQUE constraint dedupes to one ADVISORY-FRAGATTACK row per blob
even if a hypothetical future vendor-fork blob matched both entries
(impossible in practice — vendor field differs). Load-time WARN about
the duplicate advisory_id is expected and documented.

Expected corpus delta (verified pre-impl via SQL audit + post-rebuild
re-verification):
  - Curated CVE-2020-24586/87/88 rows from qualcomm/wifi blobs:
    3 CVEs × 96 blobs = 288 rows → 0
  - New ADVISORY-FRAGATTACK rows: 96 per-blob deduped rows on the
    qualcomm/wifi corpus (one per blob)
  - Tier 4 SBOM kernel-module CVE-2020-2458x rows (1076 × 3 per CVE):
    UNCHANGED (out of scope — Tier 4 SBOM matching, not curated YAML)

Net effect: 192 over-attributed curated CVE rows REMOVED; 96 advisory
rows ADDED; forensic visibility on broadcom + qualcomm WiFi blobs
preserved.

5 new paired-canary tests (Rule #46):
  - test_fragattacks_broadcom_wifi_emits_advisory_not_cve
  - test_fragattacks_qualcomm_wcn3xxx_emits_advisory_not_cve
  - test_no_curated_entry_emits_fragattacks_spec_level_cves
    (cross-corpus regression canary; fires on any future YAML edit
    that re-introduces CVE-2020-2458x as a direct attribution)
  - test_fragattacks_advisory_id_canonical_and_fits_varchar_20
  - test_fragattacks_advisory_entries_pass_forensic10_gate

Verification: 5/5 new tests pass; full FragAttacks-related test suite
continues to pass under
`uv run --frozen pytest backend/tests/test_hardware_firmware_cve_matcher.py
 -k "fragattacks or no_curated_entry_emits"`.

References:
- https://nvd.nist.gov/vuln/detail/CVE-2020-24586
- https://nvd.nist.gov/vuln/detail/CVE-2020-24587
- https://nvd.nist.gov/vuln/detail/CVE-2020-24588
- https://www.fragattacks.com

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eastmadc added a commit that referenced this pull request May 22, 2026
…ared

Reviewer B 2026-05-15-PM HIGH carried-forward from postmortem-hw-firmware-
tegra-activation-2026-05-15. Per Rule #19 recursive NVD-CPE
verification, NVD CPE narrows CVE-2023-20819 to exactly 6 MediaTek
modem-OS families: lr11 / lr12a / lr13 / nr15 / nr16 / nr17. The
hardware chipset CPEs (66 entries MT2731..MT8798) are sibling
AND-nodes describing the runtime substrate, NOT version anchors.

Pre-narrowing the entry fired on EVERY MediaTek modem blob (20 rows
current corpus) regardless of family. Post-narrowing, the
version_regex restricts firings to blobs whose `version` field
contains an NVD-CPE-affected family token.

NVD-CPE verification (recursive — implementer-side WebFetch in scout
report + this commit re-verifies regex against published CPE strings):
  - cpe:2.3:o:mediatek:lr11:-:*:*:*:*:*:*:*
  - cpe:2.3:o:mediatek:lr12a:-:*:*:*:*:*:*:*
  - cpe:2.3:o:mediatek:lr13:-:*:*:*:*:*:*:*
  - cpe:2.3:o:mediatek:nr15:-:*:*:*:*:*:*:*
  - cpe:2.3:o:mediatek:nr16:-:*:*:*:*:*:*:*
  - cpe:2.3:o:mediatek:nr17:-:*:*:*:*:*:*:*

Regex shape (boundary-aware, case-insensitive):
  (?i)(?:^|[^a-z0-9])(lr11|lr12a|lr13|nr15|nr16|nr17)(?:[^a-z0-9]|$)

Boundary check (`(?:^|[^a-z0-9])` / `(?:[^a-z0-9]|$)`) prevents false
positives on confused substrings — e.g. `nr155_else` (nr155 ≠ nr15)
and `lr12abc` (lr12abc ≠ lr12a). Tolerates dot, underscore, and
end-of-string separators per the canonical MOLY banner shapes
(MOLY.LR12A.R3.MP.V101 / MOLY_NR16_R1 / bare `lr12a`).

Forward-prepared per Tegra precedent (Pattern #3 from postmortem-hw-
firmware-tegra-activation-2026-05-15 — forward-prepared CVE pins ship
with documented activation conditions; activate via N follow-up
commits when extraction infrastructure lands). Current state:
  - mtk_modem parser DOES NOT populate blob.version with MOLY banner
    (Scout 3 verified via parsers/mediatek_modem.py:46-50 _VERSION_RES
    regex set — none of the patterns capture lr11..nr17)
  - matcher version_regex semantics are HARD REJECT (Scout 3 verified
    via cve_matcher.py:480-491; comment confirms "Stays STRICT — when
    present, version evidence MUST be found")
  - Net corpus effect post-rebuild: CVE-2023-20819 row count
    20 → 0 (BETTER than the over-attributed pre-narrowing rows per
    Reviewer B's NVD-CPE evidence; activates when mtk_modem parser
    ships version-banner extraction in a future session)

5 new paired-canary tests (Rule #46):
  - test_cve_2023_20819_version_regex_present_and_matches_six_families
    (positive: all 6 NVD families in real-world MOLY banner shapes;
     negative: LR18/NR18/LR12 out-of-scope + confused-substring
     guards `nr155_else` and `lr12abc`)
  - test_cve_2023_20819_hard_rejects_blob_with_null_version (gate-
    canary asserts the matcher's HARD-REJECT version_regex semantics
    actually fire on NULL — without this, a silent regression to
    soft-fallback would re-introduce the over-attribution)
  - test_cve_2023_20819_fires_when_version_contains_lr12a (Rule #46
    positive-arm — confirms the gate doesn't silently drop all
    matches due to a regex bug; activates with mtk_modem parser
    shipment)
  - test_cve_2023_20819_excludes_out_of_scope_family_versions (Rule
    #46 negative-arm — even with MOLY banner present, out-of-NVD-
    scope families like LR18 must not fire)
  - test_cve_2023_20819_entry_satisfies_f_forensic_10_gate (asserts
    the entry survives the F-FORENSIC-10 load filter)

Verification: all 5 new tests pass; full cve_matcher + forensic10
alignment suite (98 tests) passes under
`uv run --frozen pytest backend/tests/test_hardware_firmware_cve_matcher.py
 backend/tests/test_forensic10_alignment.py -v`.

References:
- https://nvd.nist.gov/vuln/detail/CVE-2023-20819
- M-MOLY01068234 (MediaTek PSB)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eastmadc added a commit that referenced this pull request May 22, 2026
…mary

Reviewer B 2026-05-15-PM forensic-domain review caught CVSS field drift
on the FragAttacks advisory entries. Per Rule #19 recursive NVD-CPE
verification (extended to CVSS field values per Pattern #2 of
postmortem-hw-firmware-mcp-tegra-2026-05-15), independent NVD WebFetch
on each of the 3 SPEC-level FragAttacks CVEs confirmed:

  - CVE-2020-24586: NVD primary CVSS 3.1 = 3.5 LOW
  - CVE-2020-24587: NVD primary CVSS 3.1 = 2.6 LOW
  - CVE-2020-24588: NVD primary CVSS 3.1 = 3.5 LOW

(Verified via https://services.nvd.nist.gov/rest/json/cves/2.0?cveId=...
endpoints; primary source nvd@nist.gov for all 3.)

Both FragAttacks entries shipped pre-fixup with severity=medium /
cvss_score=6.5 — the medium 6.5 likely originated from earlier
pre-advisory-conversion drafts that referenced field-deployed operator
impact rather than NVD primary. Per the recursive discipline, NVD
primary is authoritative; operator-deployment context is a separate
flag, not a CVSS override.

Fixup:
  - broadcom FragAttacks entry: severity medium→low, cvss_score
    6.5→3.5 (worst-case of 3.5/2.6/3.5)
  - qualcomm wcn3xxx FragAttacks entry: same change
  - Inline YAML notes updated with per-CVE NVD primary scores +
    aggregation explanation

New regression canary:
  - test_fragattacks_cvss_matches_nvd_primary_per_recursive_discipline
    Pins severity=low + cvss_score=3.5 across both advisory entries;
    fires fast on future CVSS drift.

Why this matters: operators triaging "fragattacks medium 6.5" would
misprioritize vs NVD's LOW assessment. For an advisory aggregating
multiple SPEC-level CVEs, the worst-case individual NVD primary CVSS
is the standard convention — preserves comparability across the
curated/advisory tier.

Multi-persona reviewer pattern (6 sessions running) — Reviewer B's
independent NVD WebFetch caught what the implementer-side WebFetch
missed (the implementer focused on NVD vendor list for the
realignment scope; Reviewer B re-fetched and noticed the CVSS field
values had drifted too).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eastmadc added a commit that referenced this pull request May 22, 2026
Codify the cross-stack alignment test discipline as a first-class recipe.
Pairs with CLAUDE.md Rule #25 single-slice exception #2 (cross-stack-alignment
commit shape) — that rule covers the COMMIT shape; this recipe covers the
TEST shape (5 mandatory parts + asymmetry-tolerance design principle + 2
commit shapes Shape 1 multi-surface single-commit vs Shape 2 regression
canary on existing surfaces).

Closes evening:RvwC-C2 HIGH from
postmortem-hw-firmware-reviewer-followup-2026-05-15-evening.md
(ADAPTIVE_BACKLOG entry now in-progress → completed).

Rule-of-Nine evidence table inline:
- Rule-of-Eight Shape-1 baseline: 7079b4d + ee2abd9 β.12a + f70c2e1 γ.7 +
  20ea228 δ.8 + 5466644 ε.1.b.4 + da71afa ζ.1 + a6be708 ζ.2.C + 04a3c55 ζ.3.C
- 9th instance + first Shape-2: d641f28 (2026-05-15 evening) F-FORENSIC-10
  alignment canary — first explicit add-test-only commit for existing-surface
  alignment

Companions: Rule #21 (sync CLAUDE.md ↔ conventions.md ↔ .mex/patterns/),
Rule #46 META-CANARY discipline (gate's diagnostic substring must be
asserted, not just rejection), Rule #31 width-canary (surface-identification
grep run twice), Rule #19 evidence-first (asymmetry documented in module
docstring before refactoring it into a "looks symmetric" shape).

INDEX.md entry added in same commit per Rule #21 sync discipline.
~282 LOC recipe (within typical recipe size range — add-alembic-migration
is 17312 chars; this is comparable).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eastmadc added a commit that referenced this pull request May 22, 2026
Codify the forward-prepared CVE pin pattern as a first-class recipe.
Pairs with CLAUDE.md Rule #19 evidence-first + the hard-reject version_regex
matcher contract at cve_matcher.py:480-491 ("Stays STRICT — when present,
version evidence MUST be found").

Closes evening:RvwC-C7 HIGH from
postmortem-hw-firmware-reviewer-followup-2026-05-15-evening.md
(ADAPTIVE_BACKLOG entry now in-progress → completed).

Rule-of-Two evidence:
- 6bc1c1d (2026-05-15 morning) — 6 Tegra/L4T CVE pins forward-prepared for
  L4T BSP release extraction; activated via afternoon's f54d415+0a901f2+338f95b
  parser chain (4-of-6 fired on DS1; 2 correctly excluded per NVD scope).
- e45a74c (2026-05-15 evening) — MediaTek CVE-2023-20819 forward-prepared for
  MOLY banner extraction (lr11/lr12a/lr13/nr15/nr16/nr17 modem-OS families
  per NVD CPE); 20 rows over-attributed pre-narrowing → 0 rows post-narrowing
  pending mtk_modem parser shipment.

Recipe covers: WHEN to apply (NVD-CPE narrowing without extraction infra) +
WHAT to ship (YAML entry shape with inline comment header citing NVD CPE +
hard-reject contract + activation prerequisite) + boundary-anchored regex
shape `(?:^|[^a-z0-9])` for substring-confusion guards (NOT `\b` which
fails on underscore-separated banners like MOLY_NR16_R1) + gate-canary test
shape per Rule #46 + activation commit-chain plan (parser extraction →
detection re-run with DELETE-before-redetect → cve-match with surgical
DELETE before re-match → verification audit) + 10 worked steps.

Companions: Rule #19 (evidence-first NVD WebFetch), Rule #25 per-piece
commits, Rule #46 paired-canary (gate-canary REQUIRED), Pattern #5 of
evening postmortem (surgical DELETE before cve-match), Pattern #7 of
afternoon postmortem (on_conflict_do_nothing requires DELETE+redetect for
parser-output changes on existing blobs), Pattern #8 of evening postmortem
(pre/post corpus baseline audit), Pattern #9 of evening postmortem (triple-
verification scout → implementer → reviewer catches drift single-axis
verification misses; 7 sessions running durable beyond debate).

INDEX.md entry added in same commit per Rule #21 sync discipline.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eastmadc added a commit that referenced this pull request May 22, 2026
…ators

Dissect.target-shaped detect() classmethod (Scout BB §3.2). Three files:

  - base.py     ChipMatcher Protocol + register_matcher() + address-translation
                helpers (address_to_file_offset / read_word_at_address /
                read_region_bytes / domain_base_addr_for_blob) — respect
                packing per-region geometry; C28x two_bytes_per_word_le
                packing means file_offset = (addr - base) × 2 (Scout AA
                §1 attack-surface #2).
  - yaml_driven.py  Default matcher walking the catalog. Eight signal
                evaluators (silicon_id_byte_match / reset_vector_at /
                vector_table_shape / string_present / bam_signature /
                boot_header_magic / elf_magic / entropy_band) with
                closed-grammar dispatch via SIGNAL_EVALUATORS. NO regex,
                NO operator-supplied scripts (Scout CC §SC7 hard cap).
  - __init__.py register at import time, mirrors parsers/ shape.

Three sentinel scoring values:
  - REJECT (-inf): hard disqualify the candidate (elf_magic uses this)
  - NOT_APPLICABLE (NaN): signal references addresses outside blob
    coverage — excluded from both numerator AND denominator so partial
    dumps (flash-only / boot-ROM-only) don't get penalised
  - float [0..1]: partial score × signal weight = contribution

Empirical validation against Eaton TMS320F28066 production firmware
(Rule #19): stripped firmware has NO TI compiler strings (no
"Texas Instruments", "TMS320", "Piccolo" anywhere in the 256KB flash
dump). Matcher correctly returns confidence=0 — auto-detection is
honest, not made-up. The walker's primary identification path on real
production firmware will be operator-supplied hints via the
bare-metal-hint endpoint (P1.11); auto-detection works on debug/dev
builds that retain compiler strings.

23 pytest tests: signal-evaluator exhaustive-coverage META-CANARY
(Rule #46 — every DetectionSignalKind has a SIGNAL_EVALUATORS handler),
address-translation correctness for byte- + word-addressed packing,
each evaluator's happy + reject paths, REJECT short-circuit,
NOT_APPLICABLE handling, threshold filtering, evidence breakdown.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eastmadc added a commit that referenced this pull request May 22, 2026
Per-surface endpoint per Scout EE §4 — `POST /api/v1/projects/{p}/firmware/{f}/bare-metal-hint`.
Generic `/external-descriptors` alias deferred to Rule-of-Two (Rule #19
evidence-first — don't generalize on a single use case).

Closes P1.11. The Velociraptor / dissect / custom-ingestor protocol
Phase 1 deferred. Operators consume via the existing
`submit_bare_metal_descriptor` MCP tool (same service layer; different
transport).

Rule #33 .a contract:
  - Idempotent on (firmware_id, ingestor_id, descriptor_hash)
  - Same hash → 200 idempotent replay (same descriptor_id returned)
  - Different hash from same ingestor → 409 conflict + prior_descriptor_id
  - Hash excludes received_at — replays across days = same descriptor

Rule #51 rate-limit: TIER_A_LIGHT_ACK (30/hour). Sub-second ACK,
walker auto-trigger fires detached (deferred to Phase 2.5 — operator
explicitly triggers via audit_bare_metal_firmware MCP for now).

_EXPECTED_TIERS extended in test_rate_limit_tiers.py with the bare-metal
endpoint; count bumped 10 → 11 with size-lock assertion.

HTTP smoke matrix — all 5 cases pass on live backend:
  - 201 Created (new descriptor, ti/tms320f28066, descriptor_hash returned)
  - 200 OK (idempotent replay, status=idempotent_replay, same descriptor_id)
  - 409 Conflict (different family same ingestor, prior_descriptor_id +
    actionable hint about supersedes_id Phase 2.5 feature)
  - 422 Unprocessable (unknown family — structured detail with
    known_families list + operator hint about catalog YAML)
  - 404 Not Found (nonexistent firmware)

Trust model (Phase 1): global API key → descriptor_source =
unauthenticated_external. Per-ingestor scoped keys + attested_external
ship in Phase 3 (Scout EE §5.4) when a second external integration
partner arrives.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eastmadc added a commit that referenced this pull request May 22, 2026
…ntel HEX + SREC YAMLs + A8 high-collision floor (P3.2.b)

Closes P3.1 deferral (postmortem item 5 — Intel HEX text_format evaluator
stub). Per Wave-1 S4 design + Wave-2 W2-α convergence + W2-β §SC5-NEW-2
safety floor.

Closed-grammar schema (Rule #52):

* New `TextFormatCharset` Literal (6 values): hex_upper / hex_lower /
  hex_mixed / hex_space_separated (W2-α addition for future
  space-delimited formats) / ascii_printable / base64_url.
* New `TextFormatLineTerminator` Literal: lf / crlf / cr / any.
* New `TextFormatFirstLine` Literal: record_start / any.
* New `TextFormatConstraint` Pydantic sub-model — 8 fields, all closed
  or bounded numeric (record_start_byte_hex single-byte; min/max line
  length [4,4096]; min_first_block_records [1,64]; optional
  header_pattern_hex + terminator_record_hex bounded-hex strings).
  Constraint-strength floor model_validator rejects min_records<2 +
  min_line<8 (W2-β §SC5-NEW-2 mitigation).
* DetectionSignal extended with `text_format_constraint: Optional`
  field; signal-level model_validator REQUIRES constraint when
  kind="text_format" + REJECTS constraint on non-text_format kinds.

Resolver evaluator implementation (`_eval_text_format` replaces P3.1.b
stub):

* `_TEXT_FORMAT_CHARSET_BYTES`: closed dispatch table mapping each
  charset Literal to a frozen byte set. Rule #46 META-CANARY enforces
  exhaustive coverage.
* `_TEXT_FORMAT_TERMINATORS`: same shape for line_terminator.
* Detection-only — validates first N records' shape (record_start_byte
  + charset + line_length); tail scan for optional terminator_record_hex.
* Cost-class=1 (cheap); bounded by min_first_block_records<=64 *
  max_line_length<=4096 = ~263KB worst-case byte comparisons.
* Defensive — every parse failure returns False; no exception propagation.

A8 catalog-load gate (Wave-2 W2-β §SC5-NEW-2 high-collision floor):

* FileFormatManifest._check_cross_field_invariants: operator-supplied
  text_format signal with charset=ascii_printable from non-_system
  source requires precedence >= 5000. Prevents the "operator declares
  effective always_matches without the flag" attack surface (operator
  with record_start_byte=' ' + ascii_printable + min_records=3 matches
  every text file).
* _system source ascii_printable is unrestricted; operator hex_mixed
  is unrestricted (charset itself provides discrimination).

Three (now two) new `_system/` YAMLs:

* `_system/intel_hex.yaml` UPDATED — text_format_constraint block with
  record_start=':' (3a) / hex_mixed / line_terminator=any /
  min_line_length=11 / max_line_length=521 /
  min_first_block_records=4 / terminator_record_hex=`:00000001FF\\n`.
* `_system/motorola_srec.yaml` NEW — record_start='S' (53) / hex_mixed /
  min_line_length=10 / max_line_length=515 / min_first_block_records=4.
  No terminator_record_hex (S7/S8/S9 family varies by address size;
  4-record-shape match is sufficient).
* `_system/ti_txt.yaml` DEFERRED — TI-TXT block-header format (where
  only the `@<addr>` line carries the marker; subsequent data lines
  don't) doesn't fit the strict per-record evaluator without a new
  `block_header` Literal value on `first_line_must_match`. Defer to
  P3.x where the chip_family TI C28x walker wiring lands AND the
  block-mode extension ships together (Rule #19 evidence-first +
  Rule #28 yardstick).

Tests (24 new in test_text_format_evaluator.py):

* Positive: Intel HEX + SREC valid blobs accept via direct evaluator
  + via catalog `resolve()`.
* Negative: non-marker first line / too-few-records / charset
  violation / corrupted-terminator / empty blob / line-too-short.
* Negative resolve(): binary blob with .hex extension falls to
  linux_blob floor sentinel (proves the closed-grammar evaluator
  ACTUALLY rejects binary noise).
* Schema rejection: text_format without constraint / constraint on
  non-text_format / weak constraint (min_records<2 + min_line<8) /
  min_line > max_line.
* A8: operator+ascii_printable+precedence<5000 REJECTED;
  operator+ascii_printable+precedence>=5000 ACCEPTS;
  _system+ascii_printable accepts at any precedence;
  operator+hex_mixed+precedence<5000 accepts (charset discriminates).
* M5 paired META-CANARY (Rule #46): AST-walk `_eval_text_format`
  body; assert NO hardcoded byte literals (b":" / b"S" / b"@") —
  every byte comparison MUST go through `signal.text_format_constraint`.
  Allowlist b"" + b"\\n" + b"\\r" + b"\\r\\n" (terminator-stripping
  mechanical constants).
* M5 paired canary: synthesized hostile evaluator body with b":"
  literal; assert M5 assertion would REJECT.
* M6a/M6b paired: _TEXT_FORMAT_CHARSET_BYTES / _TEXT_FORMAT_TERMINATORS
  exhaustive against the closed Literals; paired synthetic-missing-key
  canary.

Acceptance:
  grep -c "TextFormatConstraint" backend/app/schemas/file_format.py = 4
  find backend/app/services/file_format_catalog/data/file_formats/_system \\
    -name 'intel_hex.yaml' -o -name 'motorola_srec.yaml' | wc -l = 2
  grep -c "_TEXT_FORMAT_CHARSET_BYTES\\|_TEXT_FORMAT_TERMINATORS" \\
    backend/app/services/file_format_catalog/resolver.py = 4

Validation:
  Rule #11: import smoke verified: TextFormatConstraint instantiable,
    DetectionSignal validator fires correctly, charset+terminator tables
    exhaustive, Intel HEX + SREC resolve via catalog.
  Targeted: 348/348 pass across the file-format + classifier suites.
  New tests: 24/24 pass in test_text_format_evaluator.py.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eastmadc added a commit that referenced this pull request May 22, 2026
Structured postmortem for the 6 P3.2 commits (34d0689..007abf3) closing
all 5 P3.1 deferrals (postmortem items 2-5 + 8-9) per the deep-research
+ Citadel + per-piece commit cadence that shipped P3.1.

Captures:

* 6/6 phases shipped (P3.2.a sort_tier + precedence-flip + bridge
  removal; P3.2.b TextFormatConstraint + Intel HEX + SREC + A8;
  P3.2.c RTOS plugin wiring HYBRID + by_rtos_family + A6/A7/A9;
  P3.2.d container precedence docs + windows_cab disambig drop;
  P3.2.e parity test -> JSON snapshot; P3.2.f Rule #52 Rule-of-Two
  + Wave-2 methodology + .mex sync).

* 5 "What Broke" entries (all caught in-session by tests/canaries):
  P3.2.a flip exposing 4 latent regression sites; 12 _system fixtures
  needing sort_tier:floor; terminator_record_hex byte-count error;
  TI-TXT block-header format incompatibility (deferred per Rule #19
  + Rule #28); A6 dispatch-rank-monotonicity catching rtos_dispatch's
  default=rtos_blob attestation split.

* 16 safety-system catches table: schema validators, A6/A7/A8/A9
  catalog-load gates, per-tier cardinality, Rule #46 META-CANARIES
  M1/M3/M5/M7/M8 with paired canaries, Wave-2 W2-beta cross-feature
  critique (3 NEW SC5 analogs), W2-alpha convergence, W2-gamma Rule #28
  yardstick.

* 8 patterns: Wave-2 cross-feature critique surfaces attacks Wave-1
  can't (Rule-of-Two now); closed-grammar Pydantic + free-string
  taxonomy + plugin escape hatch is the Rule-of-Two shape; user-
  direction repetition (4x) is a strong implementation signal;
  bridge-still-needed cases document themselves via the
  disambiguation set; A6/A7/A9 gates land in same commit as consumer;
  per-piece direct-push + bisect-clean is Rule-of-Three now;
  single-slice cross-stack exception covers atomic-multi-surface
  changes; TI-TXT deferral via Rule #19 + Rule #28 worked.

* 8 recommendations: P3.3.a delete 3 legacy shim modules;
  P3.x substring_in_head signal kind; P3.x Refinement.stem_category_map;
  P3.x TI-TXT YAML + block_header Literal; P3.x per-family RTOS YAMLs;
  P3.x arq worker on_startup; P4 WAIRZ_FORMAT_PLUGIN_PATH side-container;
  CLAUDE.md Rule #52 worked-examples table kept growing.

* Numbers table: +2,876/-187/+2,689 net across 30 files; 87 new tests
  (26+24+31+6); 348/348 pass on in-scope sweep; 49 manifests (was 47);
  23 closed Literals (was 18); 9 catalog-load gates (was 5); 60+ paired
  META-CANARIES; 0.18x P3.1 drift well under Rule #28 yardstick;
  0 reverts / 0 circuit-breaker trips / 0 quality-gate blocks.

CLAUDE.md Rule #52 PROMOTED: Rule-of-One -> Rule-of-Two DURABLE BEYOND
DEBATE. Rule-of-Three eligibility on the next adaptable-extension
surface (decoder family / vendor adapter / ICS protocol / JTAG TAP /
USB descriptor families).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eastmadc added a commit that referenced this pull request May 22, 2026
…try-p32-2026-05-19

Post-campaign pattern + anti-pattern extraction per /citadel:learn skill:

* `.planning/knowledge/file-format-yaml-registry-p32-2026-05-19-patterns.md`
  — 13 successful patterns (Wave-1+Wave-2 separation; closed-grammar
  Pydantic + free-string taxonomy + plugin escape hatch; user-direction
  repetition as load-bearing signal; bridge-still-needed cases via
  disambiguation set; A-gates co-locate with consumers; per-piece direct-
  push Rule-of-Three; single-slice cross-stack exception; Rule #19+#28
  deferral; AST-walk anti-hardcode META-CANARY; tokenize-based plugin
  source scan; ContextVar for evaluator → dispatch evidence; soft
  advisory frozenset for free-string taxonomy; per-tier cardinality
  table) + 10 key decisions in a table form.

* `.planning/knowledge/file-format-yaml-registry-p32-2026-05-19-antipatterns.md`
  — 10 anti-patterns (4 rejected-at-design-time: naive is_always_match
  flag; closed RTOS_FORMAT_MAP; more_specific_than DAG; WAIRZ_FORMAT_PLUGIN_PATH
  without side-container) + 6 caught-in-session (terminator_record_hex
  byte-count error; TI-TXT block-header incompatibility; rtos_dispatch
  default attestation split; 12 fixture migrations; 4 tests pinning to
  pre-flip behavior; linux_blob removal too aggressive).

* `.claude/harness.json` — 3 new high-confidence quality rules:
  - auto-file-format-p32-1-plugins-no-subprocess: bundled
    file-format plugins MUST NOT import subprocess / requests /
    httpx / aiohttp / socket / urllib (Rule #36 + Rule #45 + M8
    META-CANARY discipline, defense-in-depth at edit time).
  - auto-file-format-p32-2-system-dispatch-default-rank-check:
    _system/*.yaml manifest declaring dispatch.default pointing to a
    core-tier format_id triggers A6 dispatch-rank-monotonicity
    WARN at catalog load; harness flags at YAML-edit time.
  - auto-file-format-p32-3-text-format-evaluator-no-hardcoded-bytes:
    hardcoded byte literals in resolver.py text-format evaluator
    violate M5 anti-hardcode (allowlist b'' + b'\\n' + b'\\r' +
    b'\\r\\n' which are mechanical terminator constants).

7 harness rules now in `qualityRules.custom` for the file-format
catalog surface (4 from P3.1 + 3 from P3.2). These complement the
schema validators (parse-time), catalog-load gates A1-A9 (load-time),
and Rule #46 META-CANARIES (test-time) with edit-time author hints.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eastmadc added a commit that referenced this pull request May 22, 2026
… (L4T BSP)

Locks in the SBOM completeness fix shipped at commit 88b3826
(2026-05-22): find_filesystem_root_strict returns None when no
Linux-rootfs markers are found instead of falling back to entry-count
guessing. The post-recursion re-probe at
firmware_service._post_process_pipeline:657-660 now falls back to the
OUTER extraction_dir, preserving the DS1 Moto super.img path (real
ext4 surfaces, strict probe returns it) AND closing the L4T BSP
regression (no rootfs markers, strict probe returns None, fs_root
stays at the outer container so detection_roots can sweep every
sibling archive subdir).

5 primary scenarios + 5 Rule #46 META-CANARY companions
(10 tests total):

  a. find_filesystem_root_strict_returns_none_on_no_markers
     + META-CANARY: ..._canary_marker_dir_detected
  b. find_filesystem_root_strict_picks_priority_marker_over_entry_count
     + META-CANARY: ..._canary_picks_higher_priority_marker (_FS_ROOT_NAMES)
  c. find_filesystem_root_strict_l4t_bsp_shape (full L4T fixture)
     + META-CANARY: ..._canary_l4t_with_rootfs_present (DS1 Moto path)
  d. find_filesystem_root_picks_entry_count_when_no_markers (legacy)
     + META-CANARY: ..._canary_returns_marker_when_present
  e. test_post_recursion_fallback_to_extraction_dir
     + META-CANARY: ..._canary_real_rootfs_wins_over_outer

Rule mappings:
- Rule #46: each absence-asserting gate has a synthesised positive
  companion; without the canary, a regression that always returns
  None (or always picks the outer dir) would silently pass the
  primary test.
- Rule #19: L4T BSP fixture mirrors the actual layout documented in
  commit 88b3826 (87-stub bootloader/ + nv_tegra/l4t_deb_packages/
  + kernel/dtb/ + sibling tegraflash archive).
- Rule #25: single-slice regression-canary commit (Shape 2 — gate on
  existing surfaces).
- Rule #38: absolute paths via pytest tmp_path throughout.

Validation:
- pytest tests/test_unpack_common_filesystem_root.py -v -> 10/10 PASS
- Deliberate-regression smoke: stubbed find_filesystem_root_strict
  to always return "fake/path" -> 10/10 FAIL (suite has teeth);
  reverted, 10/10 PASS restored.
- pytest tests/test_find_filesystem_root.py -> green (no regression
  in the adjacent raw-image-fallback suite).
- pytest tests/test_firmware_paths.py -> 72 pass, 1 pre-existing
  failure in test_sibling_archive_extracted_dirs_both_become_roots
  (Scout B's detection-roots BSP-name predicate change, in-flight,
  out of scope for this commit per task instructions).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eastmadc added a commit that referenced this pull request May 22, 2026
Operator reported missing CVE-2021-1071 (Tegra kernel INA3221 driver,
all L4T versions prior to r32.5). NVD audit swept the surrounding
NVIDIA security bulletin disclosure batch and added 18 sibling CVEs.

NEW CVEs pinned (each verified via independent NVD WebFetch per
Rule #19 evidence-first; CNA primary CVSS per evening-postmortem
2026-05-15 discipline):

  Group A — TX1-only Trusty heap (HIGH, 1 CVE):
    * CVE-2021-34373 (CNA 7.9 HIGH; Trusty heap-hardening)

  Group B — TX1-only TLK kernel family (MEDIUM, 7 CVEs, worst-case 6.7):
    * CVE-2021-34381 (tz_map_shared_mem int overflow)
    * CVE-2021-34382 (tz_map_shared_mem arbitrary kernel write)
    * CVE-2021-34385 (length-calc int overflow)
    * CVE-2021-34386 (calloc size int overflow)
    * CVE-2021-34387 (TrustZone DRAM identity-map RWX)
    * CVE-2021-34390 (SMC int overflow DoS)
    * CVE-2021-34391 (SMC int overflow DoS, sister of -34390)

  Group C — TX2/Xavier Trusty TA family (HIGH, 5 CVEs, all 7.7):
    * CVE-2021-34374 (TA cmd handler buffer length unchecked)
    * CVE-2021-34375 (TA stack cookie not randomized)
    * CVE-2021-34376 (HDCP TA cmd 5 bounds-check)
    * CVE-2021-34378 (HDCP TA cmd 11 bounds-check)
    * CVE-2021-34379 (HDCP TA cmd 10 I/O buffer length)

  Group D — TX2/Xavier Trusty OTE bounds-check (MEDIUM, 1 CVE):
    * CVE-2021-34389 (CNA 5.0)

  Group E — TX2/Xavier MB2 secure-boot heap overflow (HIGH, 1 CVE):
    * CVE-2021-34380 (CNA 7.0; sister to CVE-2021-34397 but
      far higher impact — code-exec DURING secure boot)

  Group F — TX2/Xavier MB2 heap overflow (MEDIUM, 2 CVEs, worst-case 6.4):
    * CVE-2021-34383 (CNA 6.4)
    * CVE-2021-34384 (CNA 6.3)

  Group G — ALL-Jetson TegraBoot heap overflow (MEDIUM, 1 CVE):
    * CVE-2021-34388 (broadest scope of MB2/TegraBoot family —
      all TX1+TX2+AGX-X+X-NX+Nano+Nano2G per NVD CPE)

  Group H — ALL-Jetson kernel INA3221 driver (MEDIUM, 1 CVE):
    * CVE-2021-1071 (operator-named; UNIQUE versionEndExcluding=
      r32.5 NOT r32.5.1; INA3221 ACL bypass → info disclosure)

Rule #50 shared-scope grouping: 19 CVEs → 8 pins via shared
(chipset_regex, version_regex, category, severity). Per evening-
postmortem 2026-05-15 Pattern #1, cvss_score = worst-case
individual within each group.

Rule #49 forward-prepared: pins activate the moment a future
Tegra parser enhancement extracts L4T release banners (no YAML
edit required at activation). Hard-reject contract at
cve_matcher.py:480-491 ensures ZERO over-attribution until then.

CVE-2021-1072 EXCLUDED: candidate-list named but NVD CPE is
GeForce Experience (Windows GameStream rxdiag.dll), NOT Tegra
per Rule #19 evidence-first.

Rule #25 single-slice exception #2 — cross-stack alignment commit:
YAML pins + 9 regression tests ship as one atomic commit because
the existing Tegra-pin alignment suite (test_tegra_cve_pins_*)
already enforces pairwise contract agreement on the SAME schema
fields the new pins extend.

Tests added (test_hardware_firmware_cve_matcher.py):
  * test_l4t_pre_r325_new_cve_pins_all_present
  * test_l4t_pre_r325_new_cve_pins_satisfy_f_forensic_10_narrowing
  * test_l4t_pre_r325_new_cve_pins_carry_nvd_url
  * test_cve_2021_1071_uses_r325_envelope_not_r3251 (Rule #46 META-CANARY:
    r32.5.0 IS pre-fix for -34372 but IS the fix for -1071)
  * test_cve_2021_1071_chipset_omitted_per_nvd_all_jetsons
  * test_l4t_pre_r325_new_cve_pins_cvss_match_nvd_cna_primary
  * test_l4t_pre_r325_tx1_only_pins_exclude_tx2_xavier_nano
  * test_l4t_pre_r325_tx2_xavier_pins_exclude_tx1_and_nano
  * test_l4t_pre_r325_all_jetson_pins_have_no_chipset_regex

Validation:
  * known_firmware.yaml loads 74 families clean (was 66) with
    zero F-FORENSIC-10 rejections — all 8 new pins satisfy the
    narrowing-fields gate (chipset_regex + version_regex OR
    category + version_regex)
  * pytest tests/test_hardware_firmware_cve_matcher.py — 95 passed
  * pytest tests/test_forensic10_alignment.py tests/test_nvidia_tegra_patterns.py
    tests/test_tegra_blob_parser.py — 113 passed
  * version_regex sanity-checked against operator's R32.3.1 firmware
    string + R32.4.4 (last pre-r32.5) + R32.5.0 (pre-fix for Trusty
    cluster, IS-fix for -1071) + R32.5.1 / R32.6.x / R32.7.x
    (correctly excluded)

NVD references (one per CVE):
  https://nvd.nist.gov/vuln/detail/CVE-2021-1071
  https://nvd.nist.gov/vuln/detail/CVE-2021-34373
  https://nvd.nist.gov/vuln/detail/CVE-2021-34374
  https://nvd.nist.gov/vuln/detail/CVE-2021-34375
  https://nvd.nist.gov/vuln/detail/CVE-2021-34376
  https://nvd.nist.gov/vuln/detail/CVE-2021-34378
  https://nvd.nist.gov/vuln/detail/CVE-2021-34379
  https://nvd.nist.gov/vuln/detail/CVE-2021-34380
  https://nvd.nist.gov/vuln/detail/CVE-2021-34381
  https://nvd.nist.gov/vuln/detail/CVE-2021-34382
  https://nvd.nist.gov/vuln/detail/CVE-2021-34383
  https://nvd.nist.gov/vuln/detail/CVE-2021-34384
  https://nvd.nist.gov/vuln/detail/CVE-2021-34385
  https://nvd.nist.gov/vuln/detail/CVE-2021-34386
  https://nvd.nist.gov/vuln/detail/CVE-2021-34387
  https://nvd.nist.gov/vuln/detail/CVE-2021-34388
  https://nvd.nist.gov/vuln/detail/CVE-2021-34389
  https://nvd.nist.gov/vuln/detail/CVE-2021-34390
  https://nvd.nist.gov/vuln/detail/CVE-2021-34391

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eastmadc added a commit that referenced this pull request May 22, 2026
Adds backend/app/services/hardware_firmware/parsers/_kernel_ikconfig.py
as the single source of truth for IKCFG_ST / IKCFG_ED magic bytes,
embedded .config extraction, CONFIG_* line parsing, and Linux banner
detection — used by both:

- app/ai/tools/security.py (MCP tool path for ad-hoc operator audits)
- parsers/kernel_image.py (per-blob parser — landing in the next commit)

Wave-2 critique attack F mitigation
-----------------------------------
The pre-existing _extract_ikconfig in security.py used unbounded
gzip.decompress(blob), which a malicious kernel image can leverage as
a gzip-bomb (small compressed input → multi-GB decompressed output →
worker OOM). The lifted helper uses gzip.GzipFile.read(_MAX) with a
4 MB cap (typical .config is 100-300 kB, so 4 MB is comfortably above
real-world while bounding the bomb path). Live canary against a
5 MB-expanded bomb returns None.

Real-world canary (Rule #35b)
-----------------------------
Tested against the real 34 MB DS1 Tegra L4T Image:

- IKCFG marker present at offset 15647088 (start) / 15684855 (end)
- Extraction yields 165664 bytes of .config text
- parse_kernel_config_lines() returns 5293 CONFIG_* entries
- find_linux_banner() recovers kernel_semver "4.9.140" from banner
  "Linux version 4.9.140-tegra (buildbrain@mobile-u64-1935) ..."

Key configs visible for downstream Findings emission:
  CONFIG_RANDOMIZE_BASE=y       (KASLR on)
  CONFIG_DEVMEM=y               (risk surface PRESENT — finding)
  CONFIG_DEVKMEM=y              (high-risk surface PRESENT — finding)
  CONFIG_MODULE_SIG=n           (integrity FAIL — finding)
  CONFIG_TRUSTY=y               (confirms Trusty CVE-pin gate)
  CONFIG_HARDENED_USERCOPY=y    (good)
  CONFIG_STACKPROTECTOR_STRONG  (NOT in config — hardening miss)

Rationale per CLAUDE.md
-----------------------
- Rule #19 (evidence-first) — verified bytes against a real Image
  before authoring the helper body
- Rule #36 (no-execute) — parse-only; helper never spawns subprocesses
- Rule #45 + #46 (META-CANARY) — the gzip-bomb mitigation has paired
  positive + negative tests in the smoke; formal test fixtures land
  in the parser commit

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eastmadc added a commit that referenced this pull request May 22, 2026
…uz / Image)

Registers 4 parsers under FORMAT keys already emitted by
firmware_patterns.yaml — zImage / uImage / vmlinuz / Image (the last
one is the Tegra L4T raw ARM64 Image case that motivated this work).
All four dispatch to a single `_parse_kernel_image()` body that:

(a) Reads up to 64 MB of the blob (matches dtb.py precedent; detector
    caps outer at 128 MB).
(b) Captures the `Linux version ` banner — extracts kernel_semver
    ("4.9.140" from "Linux version 4.9.140-tegra (...) (gcc 7.3.1)")
    so the cve_matcher Tier 4 kernel_cpe path can correlate.
(c) Scans for IKCFG_ST / IKCFG_ED markers via the shared helper
    (commit f947b59), decompresses the embedded gzipped .config, and
    parses it into a CONFIG_FOO → 'y'|'m'|'n'|value dict.
(d) Sets vendor (Rule #19 content-evidence override) from filename or
    banner — initial patterns cover NVIDIA / MediaTek / Qualcomm /
    Broadcom / Samsung.

ParsedBlob.metadata fields populated:
  kernel_banner       — full "Linux version ..." string
  kernel_semver       — leading SemVer for CVE matcher
  ikconfig_present    — True iff IKCFG extraction succeeded
  ikconfig_size       — decompressed .config size in bytes
  kernel_config       — dict[str, str] of all CONFIG_* entries
  kernel_config_count — len(kernel_config)
  kernel_localversion — CONFIG_LOCALVERSION value (rare; banner usually wins)

Parser stays parse-only (Rule #45) — surfaces metadata, never invokes
the kernel binary. Walker landing in a separate PR will consume
`metadata.kernel_config` and emit Findings via FindingService for
insecure / weak / missing hardening configs.

Wave-2 critique mitigations
---------------------------
- Attack D (OOM on 100 MB+ blob): _MAX_KERNEL_BYTES = 64 MB cap
- Attack F (IKCFG gzip-bomb): handled in shared helper (commit f947b59)

Live canary on the real 34 MB DS1 Tegra Image (Rule #35b)
---------------------------------------------------------
$ get_parser('Image').parse('/data/.../kernel/Image', magic, 34191368)
  ParsedBlob(
    version='4.9.140',
    vendor='nvidia',
    metadata={
      ikconfig_present=True,
      kernel_config_count=5293,
      kernel_semver='4.9.140',
      kernel_banner='Linux version 4.9.140-tegra (buildbrain@...) (gcc 7.3.1) ...',
    },
  )

Malformed-input canary returns ikconfig_present=False with NO
exception per the Parser MUST NOT raise base.py contract.

Pre-fix vs post-fix
-------------------
Pre: get_parser("Image") returned None → empty ParsedBlob() flowed
through the detector; hardware_firmware_blob row had no kernel_semver
and no kernel_config visible to the cve_matcher Tier 4 path.

Post: hardware_firmware_blob.metadata_ now carries the full
kernel_config dict + kernel_semver, unlocking the downstream
linux_kernel_hardening_walker (next PR) to emit Findings against
DS1 firmware e6e45f24 + 295eaf7a immediately on next re-detection.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eastmadc added a commit that referenced this pull request May 22, 2026
Adds the synthetic kernel-image fixture builder + 10 tests covering
the parser:

- Registry contains all 4 new FORMAT keys (zImage / uImage / vmlinuz / Image).
- Parametric extract-test across all 4 formats — same parse() body.
- Banner-only path (CONFIG_IKCONFIG=n, no embedded config).
- Vendor inference from banner ("tegra" substring → 'nvidia') per Rule #19.
- Wave-2 attack F mitigation: a 5 MB-decompressed gzip-bomb payload
  is rejected by the helper's _MAX_CONFIG_BYTES = 4 MB cap; the parser
  returns ikconfig_present=False (NOT OOM).
- Rule #45 parse-only gate: tokenize the parser source + assert no
  decrypt / subprocess.run / os.system / asyncio.create_subprocess_*
  tokens are present (whitespace-tolerant regex per κ.D lesson).
- Rule #46 META-CANARY companion: synthesise a forbidden pattern,
  tokenize it, prove the gate's regex DOES catch it. Without this
  canary the gate is a Rule #17 silent-pass risk.

Fixture builder
---------------
`build_minimal_kernel_image(config_text, version, banner_extra,
include_ikcfg, ...)` synthesises a kernel image with:
  <padding> "Linux version X.Y.Z" \0 <padding> IKCFG_ST <gzip(.config)> IKCFG_ED

Default config_text exercises all three line shapes the parser
handles:
  CONFIG_FOO=y              → 'y'
  CONFIG_FOO="value"        → '"value"' (raw)
  # CONFIG_FOO is not set   → 'n'

Verification
------------
$ uv run pytest tests/test_hardware_firmware_parsers.py
============================== 52 passed in 1.48s ==============================

Out of 52 tests, 10 are new (8 kernel_image cases + 4 malformed-byte
parametric entries × 4 new formats overlap = 4 net new) and all
pre-existing 42 still pass — no regressions in the parser fleet.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eastmadc added a commit that referenced this pull request May 22, 2026
 with config_required

Closes postmortem recommendation #4. Three new curated CVE pins using
the ``config_required`` narrowing field shipped in the previous commit
(79aac27). Each pin is NVD-verified (Rule #19 evidence-first via
per-CVE WebFetch on nvd.nist.gov/vuln/detail/<id> on 2026-05-22) —
CVSS scores + version ranges sourced from NVD CPE Known-Affected
configurations, NOT scout extrapolation.

* **CVE-2022-0185** — Linux Filesystem Context heap overflow (CVSS 8.4
  HIGH). Affected 5.1 through 5.16.1; patched in 5.16.2 / 5.15.16 /
  5.10.93 / 5.4.173. Gated on ``CONFIG_USER_NS=y``.
  version_regex precisely excludes 5.16.2+ (the patched release line);
  accepts some over-attribution within 5.1-5.15.x patched sub-versions.

* **CVE-2021-29154** — Linux BPF JIT branch displacement (CVSS 7.8 HIGH
  NVD-primary, **NOT** 8.8 as initially drafted per scout — Reviewer-
  style NVD-primary discipline per Rule #50 FragAttacks precedent).
  Affected 3.0 through 5.11.12; gated on BOTH ``CONFIG_BPF=y`` AND
  ``CONFIG_BPF_JIT=y`` (the bug is in JIT branch math; interpreter-only
  kernels pass cleanly). NVD does NOT explicitly cite the CONFIGs as
  gating but the bug is structurally JIT-only.

* **CVE-2024-0582** — io_uring buffer-ring use-after-free (CVSS 7.8
  HIGH). Affected 6.4 through 6.6.4; patched in 6.6.5 / 6.7-rc4. Gated
  on ``CONFIG_IO_URING=y``. NVD does NOT explicitly cite the CONFIG
  but io_uring is build-config-gated.

All pins use ``vendor_regex: ".+"`` (any non-empty vendor) — Linux
kernel blobs in wairz are vendor-tagged by the parser's source-of-truth
(``nvidia`` / ``yocto`` / ``openwrt`` / etc per
``kernel_image.py:167 _infer_kernel_vendor``), NOT vendor-tagged
``linux``. Three other narrowing dimensions (vendor_regex + category
exact + version_regex + config_required) satisfy F-FORENSIC-10 schema
gate (≥1 narrowing required for CVE-bearing entries).

Live canary on DS1 firmware 295eaf7a (kernel/Image blob 9456e9ac,
kernel 4.9.140, CONFIG_USER_NS=y, CONFIG_BPF=y, CONFIG_BPF_JIT=y,
CONFIG_IO_URING=absent) confirmed Rule #46 META-CANARY both
directions:

* CVE-2021-29154 FIRES: version 4.9.140 matches 3.x|4.x|5.0-5.11 range
  AND both BPF configs present → accept (high/high).
* CVE-2022-0185 REJECTS: version 4.9 not in 5.x range → version_regex
  hard-rejects.
* CVE-2024-0582 REJECTS: CONFIG_IO_URING absent from kernel_config
  dict → config_required hard-rejects. ✓ Gate semantic verified end-
  to-end against a real ORM row.

Regex correctness verified locally against 23 expected-affected /
expected-not-affected test cases: 0 failures.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
eastmadc added a commit that referenced this pull request Jun 11, 2026
…oss-ref

Grounding the real EMBA S118 (busybox-verifier) output (Rule #19)
disqualified the planned "one genuinely-new CLEAR lane" (S118 applet-absence
-> function_not_linked). Three soundness failures, all Axiom-1/Axiom-2:

  1. S118 carries no CVE->applet mapping (needs a hand-curated table it
     does not supply).
  2. libbb-shared code defeats applet-set subtraction ("applet X absent"
     != "vulnerable code absent" when reachable via applet Y).
  3. (V)-marker absence is absence-of-evidence, never a clear.

A future *sound* busybox clear lane = wairz nm-bridge (real symbol absence
via readelf/nm on unstripped busybox) + a hand-curated libbb-aware
CVE->applet->symbol table. Out of scope for EMBA ingestion; queued wairz-side.

Shipped instead (defensive, Rule #53/#46): function_not_linked is now a
GATED CR-1 reachability checker (_has_nm_proof) with a paired bare-[S118]
canary, so a future heuristic FNL clear is FLAGGED not laundered
(cve-framework commit 0bd6acfc2c).

Also records Slice 5 (attack-surface -> kill-chain) as data-availability
contingent: additive/RAISE-only/zero false-clear by construction, but yield
depends on EMBA S40/S35/S100 actually populating listener data on the corpus.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
eastmadc added a commit that referenced this pull request Jun 11, 2026
…clusion at 1+2

The Slice-5 data-availability gate ran (Rule #19, against the real EMBA
install + porter fixtures) and disqualifies the slice on three grounds:

  1. Module misattribution: S40/S35/S100 are file-permission /
     http-file-discovery / command-injection static scans, NOT listener
     enumeration. Component presence is already in Slice 1's SBOM.
  2. Real attack-surface (listening ports/services) needs FirmAE L-module
     full-system emulation (L10 supports MIPS/ARM32/x86 only).
  3. Corpus is aarch64 Jetson TX2 Yocto (emulation-inapplicable) + zero
     grounded L-module output to parse -> dead-abstraction risk. The
     killchain consumer is itself wired-but-not-yet-run.

Records the EMBA-ingestion workstream CONCLUSION: ship at Slices 1+2 (both
grounded, sound, value-proven). Slice 3 (F20 reconcile) available as optional
low-value RAISE-only telemetry; Slices 4+5 disqualified.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
eastmadc added a commit that referenced this pull request Jun 11, 2026
…cision record

Records the 8-agent debate verdict: DO NOT adopt the harness as a component (an
unmaintained, LLM-at-every-stage, execution-based C/C++-source ASAN vuln-discovery
pipeline). cve-framework: ZERO adopts — its deterministic zero-LLM gates
(audit_misattribution._fp_resolved Rule #53 + _fp_meta_canary Rule #46) are
STRONGER than the harness's LLM-verifying-LLM analogs (whose judge.py fails open =
inverse of Axiom 1). wairz: 3 dependency-free pattern adoptions — ADOPT-1
(untrusted_data fencing) SHIPPED 47a7c95; ADOPT-2 (gVisor isolation) forward-
reference only with the critical Rule #37 guard (do NOT add worker egress) +
Rule #36 guard (gVisor is not an execution sandbox); ADOPT-3 deferred (Rule #19).
Plus the explicit non-slices (never integrate the pipeline / ingest its severity /
reuse judge-grade / run ASAN-on-firmware).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
eastmadc added a commit that referenced this pull request Jun 12, 2026
… alerts (no upstream patch)

GitHub Dependabot flagged 2 CRITICAL alerts on uefi-firmware (locked at 1.11):
  - GHSA-hm2w-vr2p-hq7w  heap OOB write in tiano decompressor ReadCLen
  - GHSA-2689-5p89-6j3j  stack OOB write in tiano decompressor MakeTable
Both affect <= 1.12 with NO fixed version available upstream.

Applicability (wairz's own CVE methodology applied to its own dependency): the
library is DECLARED but NEVER IMPORTED. `grep -rn "import uefi_firmware" backend/`
is empty; the only references are the format-name string "uefi_firmware" in
hardware_firmware/classifier.py:239 and a file_format_catalog YAML descriptor —
neither is the library. The planned DBX EFI_SIGNATURE_LIST use (the old pyproject
comment) went a different route (dbx_service uses asn1crypto + a custom
EFI_VARIABLE_AUTHENTICATION_2 wrapper-strip, not this lib). The vulnerable tiano
decompressor is therefore unreachable in wairz.

Fix (Rule #19 — don't carry a dormant vulnerable dep): remove uefi-firmware from
pyproject.toml. `uv lock` drops it + its orphaned transitive `future` (34
deletions, zero unrelated version bumps). If DBX volume parsing ever needs it, it
can be re-added against whatever fixed version exists then.

Resolves: GHSA-hm2w-vr2p-hq7w, GHSA-2689-5p89-6j3j

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@eastmadc eastmadc force-pushed the dependabot/npm_and_yarn/frontend/multi-7bdfbe8666 branch from 0e688c7 to 3810911 Compare June 12, 2026 14:40
eastmadc added a commit that referenced this pull request Jun 12, 2026
…evidence)

Records that the binary-axis bridge LOGIC is complete + round-trip-verified, and that R8 (the
CVE->vulnerable-function sink map needed to run the auto-clear on a real profile) is fully
data-blocked: local Yocto .patch files absent (0/167 on disk), cvelistV5/NVD cache has no
function/file-level data (0 of 2000 sampled), CVEfixes external. A .patch parser would emit an
empty map (Rule #19 dead abstraction) — not built. Documents activation paths + the unblocked
durability-layer alternative.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
eastmadc added a commit that referenced this pull request Jun 12, 2026
…oss-ref

Grounding the real EMBA S118 (busybox-verifier) output (Rule #19)
disqualified the planned "one genuinely-new CLEAR lane" (S118 applet-absence
-> function_not_linked). Three soundness failures, all Axiom-1/Axiom-2:

  1. S118 carries no CVE->applet mapping (needs a hand-curated table it
     does not supply).
  2. libbb-shared code defeats applet-set subtraction ("applet X absent"
     != "vulnerable code absent" when reachable via applet Y).
  3. (V)-marker absence is absence-of-evidence, never a clear.

A future *sound* busybox clear lane = wairz nm-bridge (real symbol absence
via readelf/nm on unstripped busybox) + a hand-curated libbb-aware
CVE->applet->symbol table. Out of scope for EMBA ingestion; queued wairz-side.

Shipped instead (defensive, Rule #53/#46): function_not_linked is now a
GATED CR-1 reachability checker (_has_nm_proof) with a paired bare-[S118]
canary, so a future heuristic FNL clear is FLAGGED not laundered
(cve-framework commit 0bd6acfc2c).

Also records Slice 5 (attack-surface -> kill-chain) as data-availability
contingent: additive/RAISE-only/zero false-clear by construction, but yield
depends on EMBA S40/S35/S100 actually populating listener data on the corpus.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
eastmadc added a commit that referenced this pull request Jun 12, 2026
…clusion at 1+2

The Slice-5 data-availability gate ran (Rule #19, against the real EMBA
install + porter fixtures) and disqualifies the slice on three grounds:

  1. Module misattribution: S40/S35/S100 are file-permission /
     http-file-discovery / command-injection static scans, NOT listener
     enumeration. Component presence is already in Slice 1's SBOM.
  2. Real attack-surface (listening ports/services) needs FirmAE L-module
     full-system emulation (L10 supports MIPS/ARM32/x86 only).
  3. Corpus is aarch64 Jetson TX2 Yocto (emulation-inapplicable) + zero
     grounded L-module output to parse -> dead-abstraction risk. The
     killchain consumer is itself wired-but-not-yet-run.

Records the EMBA-ingestion workstream CONCLUSION: ship at Slices 1+2 (both
grounded, sound, value-proven). Slice 3 (F20 reconcile) available as optional
low-value RAISE-only telemetry; Slices 4+5 disqualified.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
eastmadc added a commit that referenced this pull request Jun 12, 2026
…cision record

Records the 8-agent debate verdict: DO NOT adopt the harness as a component (an
unmaintained, LLM-at-every-stage, execution-based C/C++-source ASAN vuln-discovery
pipeline). cve-framework: ZERO adopts — its deterministic zero-LLM gates
(audit_misattribution._fp_resolved Rule #53 + _fp_meta_canary Rule #46) are
STRONGER than the harness's LLM-verifying-LLM analogs (whose judge.py fails open =
inverse of Axiom 1). wairz: 3 dependency-free pattern adoptions — ADOPT-1
(untrusted_data fencing) SHIPPED 9ed8b22; ADOPT-2 (gVisor isolation) forward-
reference only with the critical Rule #37 guard (do NOT add worker egress) +
Rule #36 guard (gVisor is not an execution sandbox); ADOPT-3 deferred (Rule #19).
Plus the explicit non-slices (never integrate the pipeline / ingest its severity /
reuse judge-grade / run ASAN-on-firmware).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Dependency updates javascript Pull requests that update javascript code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants