Files
vulncheck/tools/diagnose_scan.py
T
vulncheck 974de08b3c fix(autodesk): match AutoCAD by release, not by release year
Two halves of the same blind spot, both on a stock AutoCAD LT 2026
(build 25.1.60.0):

MISSED. The cvelistV5 registry never carried year_ver, so that path
compared the MSI build 25.1.60.0 against "2026.0.0 lessThan 2026.1.2"
and matched nothing. It is the only path that can see these CVEs at
all — CVE-2026-7405, -7406 (ADSK-SA-2026-0012) and -17550 sit at NVD
with vulnStatus "Received" and zero cpeMatch entries, so the CPE path
is blind to them by construction. Four confirmed CVEs were invisible.

NEVER CLEARS. The year came from the product name and the build was
thrown away, so every 2026 install scanned as a bare "2026" — below
every 2026.x fix bound forever. A host patched to 2026.1.2 keeps all
seven of its autocad_lt findings with no version it could reach to
drop them. Three of those seven carry a bare-year CPE at NVD with no
range at all.

Both are fixed by resolving the build to the release Autodesk actually
bounds by: 25.1.60.0 -> 2026.0.0, 25.1.172.0 -> 2026.1.2. The table is
keyed by the build's major.minor, which has to agree with the year in
the name — that one check keeps it off products numbered some other
way, so Navisworks Freedom 2025 (22.0.1411.23) still falls back to the
bare year instead of landing on an AutoCAD row.

Hypothesis that held: the year was doing two jobs it cannot do at
once — pick the release line, and say where inside it the host sits.
2026-08-13 14:04:46 +02:00

148 lines
4.9 KiB
Python

"""Is the running container actually on the current scanner code?
Copy-pasted one-liners kept failing on invisible characters picked up from
chat, so the checks live here instead. Run inside the backend container:
docker compose exec backend python tools/diagnose_scan.py
Each line states what it expects, so the output is readable without looking
anything up. A failing line means the container is running older code — every
other symptom is downstream of that.
"""
import sys
sys.path.insert(0, "/app")
CHECKS = []
def check(name, expect):
def deco(fn):
CHECKS.append((name, expect, fn))
return fn
return deco
@check("Adobe add-on is ignored", "None")
def _adobe():
from app.services.app_cve_scanner_service import resolve_product
return resolve_product(
"Asian Language And Spelling Dictionaries Support For Adobe Acrobat Reader")
@check("Teams build shapes are not compared", "[]")
def _teams():
from app.services.msrc_scan_service import affected_cves
return affected_cves([{"cve": "X", "build": "25060212643"}],
"26183.1903.4892.4448", branch_match=False)
@check("Node 24.13.1 IS affected by CVE-2026-56846", "True")
def _node():
from app.services.cvelistv5_scan_service import _affected, _ranges_from_affected
rg = _ranges_from_affected({
"vendor": "nodejs", "product": "node", "defaultStatus": "unaffected",
"versions": [{"version": "24.18.0", "lessThanOrEqual": "24.18.0",
"versionType": "semver", "status": "affected"}]})
return any(_affected("24.13.1", s, lt, lte) for s, lt, lte in rg)
@check("Node 22.23.2 is NOT affected by it", "False")
def _node_other_line():
from app.services.cvelistv5_scan_service import _affected, _ranges_from_affected
rg = _ranges_from_affected({
"vendor": "nodejs", "product": "node", "defaultStatus": "unaffected",
"versions": [{"version": "24.18.0", "lessThanOrEqual": "24.18.0",
"versionType": "semver", "status": "affected"}]})
return any(_affected("22.23.2", s, lt, lte) for s, lt, lte in rg)
@check("Browser-extension CPEs rejected on Windows", "False")
def _target_sw():
from app.services.app_cve_scanner_service import _platform_ok
return _platform_ok(["chrome"], "windows")
@check("Acrobat 26.001.21771 is NOT hit by CVE-2019-7819", "False")
def _adobe_new_scheme():
from app.services.app_cve_scanner_service import _vcmp
return _vcmp("26.001.21771", "2019.010.20098") <= 0
@check("Acrobat 19.010.20098 IS still hit by it", "True")
def _adobe_old_scheme():
from app.services.app_cve_scanner_service import _vcmp
return _vcmp("19.010.20098", "2019.010.20098") <= 0
@check("Autodesk release years are untouched", "(2026, 0, 0)")
def _autodesk_years():
from app.services.app_cve_scanner_service import _vtuple
return _vtuple("2026.0.0")
@check("AutoCAD LT 25.1.172.0 reads as the patched 2026.1.2", "2026.1.2")
def _autocad_build_map():
from app.services import cvelistv5_scan_service as c5
from app.services.app_cve_scanner_service import _effective_version
name = "Autodesk AutoCAD LT 2026 - Deutsch (German)"
return _effective_version(name, "25.1.172.0",
c5._KEY_ENTRY.get(c5.resolve(name)) or {})
@check("Teams 26183.x is NOT hit by CVE-2025-49731", "False")
def _teams_scheme():
from app.services.cvelistv5_scan_service import _affected
return any(_affected("26183.1903.4892.4448", None, b, None, scheme_strict=True)
for b in ("25060212643", "1.0.0.2025112902", "7.10.1"))
@check("Node.js reaches the cvelistV5 path", "nodejs")
def _node_resolves():
from app.services import cvelistv5_scan_service as c5
return c5.resolve("Node.js")
@check("Wazuh agent 4.14.5-1 is scannable", "4.14.5")
def _wazuh():
from app.services.app_cve_scanner_service import (
_effective_version, resolve_product)
e = resolve_product("wazuh-agent") or {}
return _effective_version("wazuh-agent", "4.14.5-1", e)
@check("cvelistV5 index key", "cvelistv5_product_index_v24")
def _index():
from app.services.cvelistv5_scan_service import _INDEX_SETTING
return _INDEX_SETTING
@check("NVD result cache prefix", "v3:")
def _cache():
from app.services.app_cve_scanner_service import CACHE_PREFIX
return CACHE_PREFIX
def main():
bad = 0
for name, expect, fn in CHECKS:
try:
got = fn()
except Exception as e:
got = f"ERROR: {e}"
ok = str(got) == expect
bad += 0 if ok else 1
print(f"[{'ok ' if ok else 'BAD'}] {name}")
print(f" expected {expect!r}, got {got!r}")
print()
if bad:
print(f"{bad} check(s) failed — this container is NOT running the current code.")
else:
print("All checks current. If findings still look wrong, the cause is "
"elsewhere — send the scan log.")
return 1 if bad else 0
if __name__ == "__main__":
sys.exit(main())