The following Python script is provided to scan, verify, or query the system telemetry:
#!/usr/bin/env python3
import csv
import json
import os
import re
import sys
from pathlib import Path
ASSET_EXPORT = Path(os.environ.get("ASSET_EXPORT", sys.argv[1] if len(sys.argv) > 1 else "sdwan-assets.csv")).resolve()
OUT = Path(os.environ.get("OUT", "hp-cisco-sdwan-cve-2026-20182-closure")).resolve()
CVE = "CVE-2026-20182"
FIXED = ["20.9.9.1", "20.12.5.4", "20.12.6.2", "20.12.7.1", "20.15.4.4", "20.15.5.2", "20.18.2.2", "26.1.1.1", "20.15.506"]
SOURCE = "https://sec.cloudapps.cisco.com/security/center/content/CiscoSecurityAdvisory/cisco-sa-sdwan-rpa2-v69WY2SW"
def vt(value):
return tuple(int(x) for x in re.findall(r"\d+", str(value))[:5])
def ge(left, right):
l, r = vt(left), vt(right)
width = max(len(l), len(r), 1)
return l + (0,) * (width - len(l)) >= r + (0,) * (width - len(r))
def row_iter(path):
if not path.exists():
raise SystemExit(f"ASSET_EXPORT not found: {path}")
if path.suffix.lower() == ".csv":
with path.open(newline="", encoding="utf-8", errors="ignore") as handle:
yield from csv.DictReader(handle)
else:
data = json.loads(path.read_text(encoding="utf-8", errors="ignore"))
if isinstance(data, list):
yield from data
else:
for key in ("assets", "devices", "controllers", "managers", "rows"):
if isinstance(data.get(key), list):
yield from data[key]
def closest_fixed(version):
candidates = [f for f in FIXED if vt(f)[:2] == vt(version)[:2] or vt(f)[0] == vt(version)[0]]
return candidates[0] if candidates else ""
OUT.mkdir(parents=True, exist_ok=True)
results = []
for idx, row in enumerate(row_iter(ASSET_EXPORT), start=1):
text = json.dumps(row, sort_keys=True)
if "Catalyst SD-WAN" not in text and "vManage" not in text and CVE not in text:
continue
match = re.search(r"(?<!\d)(20\.\d+\.\d+(?:\.\d+)?|26\.1\.\d+\.\d+)(?!\d)", text)
version = match.group(1) if match else ""
fixed_target = closest_fixed(version) if version else ""
fixed = bool(version and fixed_target and ge(version, fixed_target))
results.append({"row": idx, "cve": CVE, "source": SOURCE, "detected_release": version, "target_fixed_release": fixed_target, "fixed_release_proven": fixed, "row_data": row})
(OUT / "cisco-sdwan-cve-2026-20182-release-verification.json").write_text(json.dumps(results, indent=2, sort_keys=True), encoding="utf-8")
# Remediation trigger: fixed_release_proven false for any Catalyst SD-WAN Controller or Manager keeps CVE-2026-20182 open.
print(json.dumps({"out": str(OUT), "checked": len(results), "not_closed": [r for r in results if not r["fixed_release_proven"]]}, indent=2))