Skip to content

Commit e45a74c

Browse files
eastmadcclaude
andcommitted
feat(hw-fw): CVE-2023-20819 modem-family version_regex — forward-prepared
Reviewer B 2026-05-15-PM HIGH carried-forward from postmortem-hw-firmware- tegra-activation-2026-05-15. Per Rule digitalandrew#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 digitalandrew#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>
1 parent 54a0a32 commit e45a74c

2 files changed

Lines changed: 237 additions & 0 deletions

File tree

backend/app/services/hardware_firmware/known_firmware.yaml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,26 @@ families:
394394
vendor: mediatek
395395
category: modem
396396
category_regex: "^modem$"
397+
# Reviewer B 2026-05-15-PM HIGH: NVD CPE narrows CVE-2023-20819 to
398+
# exactly 6 MediaTek modem-OS families (lr11, lr12a, lr13, nr15,
399+
# nr16, nr17). NVD lists 66 hardware chipset CPEs (MT2731..MT8798)
400+
# as sibling AND-nodes describing the runtime substrate, not as
401+
# version anchors. version_regex below is HARD-REJECT (cve_matcher
402+
# version_regex semantics, lines ~480-491) — gate fires zero matches
403+
# until the mtk_modem parser populates blob.version with the MOLY
404+
# banner (e.g. ``MOLY.LR12A.R3.MP.V101``) OR a metadata string
405+
# carrying the family token. Forward-prepared per Tegra precedent
406+
# (postmortem-hw-firmware-tegra-activation-2026-05-15 Pattern #3 —
407+
# forward-prepared CVE pins ship with documented activation
408+
# conditions; activate via N follow-up commits when extraction
409+
# infrastructure lands).
410+
# Per Rule #19 recursive NVD-CPE verification: 6 family values are
411+
# NVD-CPE-derived (cpe:2.3:o:mediatek:{lr11,lr12a,lr13,nr15,nr16,
412+
# nr17}:-:*) NOT intuition. Eliminates the over-attribution risk
413+
# surfaced by Reviewer B: pre-narrowing, every MediaTek modem blob
414+
# fired CVE-2023-20819 (20 rows) regardless of family — post-
415+
# narrowing, only blobs with one of the 6 affected families fire.
416+
version_regex: "(?i)(?:^|[^a-z0-9])(lr11|lr12a|lr13|nr15|nr16|nr17)(?:[^a-z0-9]|$)"
397417
cves:
398418
- CVE-2023-20819
399419
severity: critical
@@ -403,6 +423,7 @@ families:
403423
from malicious base station. LR11/LR12a/LR13/NR15/NR16/NR17
404424
firmware branches affected; no extractable banner without DbgInfo
405425
sidecar (cyrozap mediatek-lte-baseband-re notes).
426+
Reference: https://nvd.nist.gov/vuln/detail/CVE-2023-20819
406427
407428
- name: MediaTek modem 5G NAS RCE cluster (Feb 2024)
408429
vendor: mediatek

backend/tests/test_hardware_firmware_cve_matcher.py

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1971,6 +1971,222 @@ def test_tegra_cve_pins_cvss_scores_match_nvd_primary() -> None:
19711971
)
19721972

19731973

1974+
# ---------------------------------------------------------------------------
1975+
# MediaTek modem CDMA PPP RCE (CVE-2023-20819) version-regex narrowing —
1976+
# Reviewer B 2026-05-15-PM HIGH carried-forward from postmortem
1977+
# hw-firmware-tegra-activation-2026-05-15. NVD CPE narrows the CVE to
1978+
# exactly 6 MediaTek modem-OS families: lr11 / lr12a / lr13 / nr15 /
1979+
# nr16 / nr17 (cpe:2.3:o:mediatek:<family>:-:* lines per the NVD JSON).
1980+
# Pre-narrowing the entry fired on every MediaTek modem blob (20 rows
1981+
# currently); post-narrowing the version_regex hard-rejects blobs whose
1982+
# `version` field doesn't match one of the 6 families.
1983+
#
1984+
# Forward-prepared per the Tegra precedent (Pattern #3 from postmortem-
1985+
# hw-firmware-tegra-activation-2026-05-15) — mtk_modem parser does not
1986+
# yet harvest MOLY family banners from modem.img blobs. Once it does,
1987+
# this pin activates without further changes. Until then, the entry
1988+
# emits zero CVE rows (better than the 20 over-attributed pre-narrowing
1989+
# rows per Reviewer B's NVD-CPE evidence).
1990+
# ---------------------------------------------------------------------------
1991+
1992+
1993+
def test_cve_2023_20819_version_regex_present_and_matches_six_families() -> None:
1994+
"""The CVE-2023-20819 entry carries a version_regex covering exactly
1995+
the 6 NVD-CPE-affected MediaTek modem-OS families.
1996+
1997+
Per Rule #19 recursive NVD-CPE verification — the regex's enumerated
1998+
values (lr11/lr12a/lr13/nr15/nr16/nr17) are NVD-CPE-derived from
1999+
direct WebFetch on services.nvd.nist.gov/.../cves/2.0?cveId=
2000+
CVE-2023-20819 (not intuition).
2001+
"""
2002+
import re as _re
2003+
2004+
families = _load_known_firmware()
2005+
fam = _find_family_by_cve(list(families), "CVE-2023-20819")
2006+
assert fam is not None, "CVE-2023-20819 entry missing from YAML"
2007+
version_re = fam.get("version_regex")
2008+
assert version_re, (
2009+
"CVE-2023-20819 entry missing version_regex — Reviewer B 2026-"
2010+
"05-15-PM HIGH realignment regression. NVD CPE narrows to 6 "
2011+
"specific modem-OS families; entry without version_regex fires "
2012+
"on every MediaTek modem blob"
2013+
)
2014+
patt = _re.compile(version_re, _re.IGNORECASE)
2015+
2016+
# Positive — the 6 NVD-CPE-affected families, in real-world MOLY
2017+
# banner shapes the mtk_modem parser will eventually emit:
2018+
positive_cases = (
2019+
"MOLY.LR11.R2.MP.V42",
2020+
"MOLY.LR12A.R3.MP.V101",
2021+
"MOLY.LR13.R1.MP.V1",
2022+
"MOLY.NR15.R1.MP.V1",
2023+
"MOLY.NR16.R1.MP.V1",
2024+
"MOLY.NR17.R1.MP.V1",
2025+
# bare lowercase forms (defensive — operator-supplied banners
2026+
# may not preserve case)
2027+
"lr12a",
2028+
"nr16",
2029+
# underscore-separated form (some parser banners use _ separator)
2030+
"MOLY_NR16_R1",
2031+
)
2032+
for s in positive_cases:
2033+
assert patt.search(s), (
2034+
f"version_regex missed NVD-scope family in {s!r} — should "
2035+
"match one of (lr11/lr12a/lr13/nr15/nr16/nr17)"
2036+
)
2037+
2038+
# Negative — out-of-scope families that NVD does NOT list:
2039+
negative_cases = (
2040+
"MOLY.LR18.MP.V1",
2041+
"MOLY.NR18.MP.V1",
2042+
"MOLY.NR12.MP.V1",
2043+
# Confused-substring guards — boundary regex must NOT match
2044+
# these even though the family token appears as a substring:
2045+
"somewhere_nr155_else", # nr155 is not nr15
2046+
"somewhere_lr12abc", # lr12abc is not lr12a
2047+
# Pre-MOLY blobs (no version evidence)
2048+
"",
2049+
)
2050+
for s in negative_cases:
2051+
assert not patt.search(s), (
2052+
f"version_regex over-matched out-of-scope family in {s!r} — "
2053+
"NVD CPE only enumerates 6 families; this regex must not "
2054+
"fire on other tokens. Risk: re-introducing over-attribution "
2055+
"Reviewer B 2026-05-15-PM flagged"
2056+
)
2057+
2058+
2059+
def test_cve_2023_20819_hard_rejects_blob_with_null_version() -> None:
2060+
"""Rule #46 gate-canary: confirms the matcher HARD-REJECTS
2061+
CVE-2023-20819 on a blob without an extractable MOLY family.
2062+
2063+
cve_matcher version_regex semantics are HARD-REJECT — when set, the
2064+
matcher requires version evidence to fire (cve_matcher.py lines
2065+
~480-491; ``Stays STRICT — when present, version evidence MUST be
2066+
found``). Soft-fallback applies to chipset_regex only. This test
2067+
confirms the gate's hard-reject path actually fires; without it, a
2068+
silent semantics regression to soft-fallback (which would re-
2069+
introduce the over-attribution Reviewer B caught) would go
2070+
undetected.
2071+
2072+
Forward-prepared: today the mtk_modem parser does NOT populate
2073+
blob.version with the MOLY banner; this test asserts the CVE row
2074+
is suppressed. When parser shipment lands, a paired positive-arm
2075+
test should land alongside (operator-targeted naming:
2076+
test_cve_2023_20819_fires_when_mtk_modem_emits_lr12a).
2077+
"""
2078+
blob = _make_blob(
2079+
vendor="mediatek",
2080+
category="modem",
2081+
version=None, # mtk_modem parser doesn't populate this today
2082+
chipset_target=None,
2083+
metadata={},
2084+
)
2085+
matches = _match_curated(blob, _load_known_firmware())
2086+
cve_ids = {m.cve_id for m in matches}
2087+
assert "CVE-2023-20819" not in cve_ids, (
2088+
"CVE-2023-20819 fired on a MediaTek modem blob WITHOUT MOLY "
2089+
"version evidence — Reviewer B 2026-05-15-PM realignment "
2090+
"regression. version_regex must HARD-REJECT on NULL version "
2091+
"to prevent over-attribution on the 20 modem blobs currently "
2092+
"in corpus that have NULL version_extracted. Investigate "
2093+
"whether matcher semantics regressed from hard-reject to "
2094+
"soft-fallback"
2095+
)
2096+
2097+
2098+
def test_cve_2023_20819_fires_when_version_contains_lr12a() -> None:
2099+
"""Rule #46 positive-arm canary: when blob.version contains an
2100+
NVD-CPE-affected family token, the CVE row IS emitted.
2101+
2102+
Forward-prepared shape: this test synthesizes the expected blob
2103+
state once the mtk_modem parser harvests MOLY banners. Confirms
2104+
the version_regex correctly fires on the in-scope shape; without
2105+
it, a regex bug that silently dropped all matches would go
2106+
undetected.
2107+
"""
2108+
blob = _make_blob(
2109+
vendor="mediatek",
2110+
category="modem",
2111+
version="MOLY.LR12A.R3.MP.V101",
2112+
chipset_target=None,
2113+
metadata={},
2114+
)
2115+
matches = _match_curated(blob, _load_known_firmware())
2116+
cve_ids = {m.cve_id for m in matches}
2117+
assert "CVE-2023-20819" in cve_ids, (
2118+
"CVE-2023-20819 did NOT fire on a MediaTek modem blob with "
2119+
"MOLY.LR12A version evidence — version_regex shape may have "
2120+
"regressed; NVD CPE explicitly lists lr12a as in-scope"
2121+
)
2122+
2123+
2124+
def test_cve_2023_20819_excludes_out_of_scope_family_versions() -> None:
2125+
"""Rule #46 negative-arm canary: blobs with out-of-NVD-scope family
2126+
(e.g. LR18 / NR18 / LR14) MUST NOT fire CVE-2023-20819.
2127+
2128+
The over-attribution risk Reviewer B flagged is firing on EVERY
2129+
MediaTek modem blob; this test asserts the in-corpus shape where
2130+
a blob HAS a MOLY family but it's outside NVD scope still produces
2131+
zero CVE-2023-20819 rows.
2132+
"""
2133+
for out_of_scope_version in (
2134+
"MOLY.LR18.MP.V1",
2135+
"MOLY.NR18.MP.V1",
2136+
"MOLY.LR14.MP.V1",
2137+
):
2138+
blob = _make_blob(
2139+
vendor="mediatek",
2140+
category="modem",
2141+
version=out_of_scope_version,
2142+
chipset_target=None,
2143+
metadata={},
2144+
)
2145+
matches = _match_curated(blob, _load_known_firmware())
2146+
cve_ids = {m.cve_id for m in matches}
2147+
assert "CVE-2023-20819" not in cve_ids, (
2148+
f"CVE-2023-20819 fired on blob with out-of-NVD-scope "
2149+
f"version {out_of_scope_version!r} — version_regex "
2150+
"appears to over-match beyond NVD's 6-family scope "
2151+
"(lr11/lr12a/lr13/nr15/nr16/nr17)"
2152+
)
2153+
2154+
2155+
def test_cve_2023_20819_entry_satisfies_f_forensic_10_gate() -> None:
2156+
"""Rule #46 gate-confirmation canary: the CVE-2023-20819 entry's
2157+
version_regex is one of the 4 narrowing-field allowlist members,
2158+
so the F-FORENSIC-10 gate accepts the entry at load time.
2159+
2160+
Confirms the realignment doesn't accidentally land in a shape
2161+
that the gate would silently reject (which would cause
2162+
CVE-2023-20819 to disappear from the loaded family list, NOT
2163+
fire on any blob, and silently regress the curated coverage).
2164+
"""
2165+
families = _load_known_firmware()
2166+
fam = _find_family_by_cve(list(families), "CVE-2023-20819")
2167+
assert fam is not None, (
2168+
"CVE-2023-20819 entry was REJECTED by the F-FORENSIC-10 gate "
2169+
"at load time — version_regex isn't satisfying the narrowing "
2170+
"requirement. Re-check the entry shape"
2171+
)
2172+
from app.services.hardware_firmware.cve_matcher import (
2173+
_KNOWN_FIRMWARE_NARROWING_FIELDS,
2174+
)
2175+
2176+
has_narrowing = any(
2177+
fam.get(field) is not None
2178+
for field in _KNOWN_FIRMWARE_NARROWING_FIELDS
2179+
)
2180+
assert has_narrowing, (
2181+
"CVE-2023-20819 entry shipped without ANY narrowing field — "
2182+
"F-FORENSIC-10 gate would reject"
2183+
)
2184+
assert fam.get("version_regex"), (
2185+
"CVE-2023-20819 entry should carry the version_regex specifically "
2186+
"(per Reviewer B 2026-05-15-PM NVD-CPE-derived narrowing)"
2187+
)
2188+
2189+
19742190
# ---------------------------------------------------------------------------
19752191
# F-FORENSIC-10 schema gate analog (Reviewer B B1 2026-05-15) — CVE-bearing
19762192
# entries MUST set at least one narrowing field beyond vendor + category

0 commit comments

Comments
 (0)