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.
148 lines
4.9 KiB
Python
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())
|