#!/usr/bin/env python3
"""Defensive scope scanner for CVE-2026-48282 (Adobe ColdFusion).
This script scans exported web, EDR, asset, ticket, or CMDB text/JSON/CSV data for
source and product selectors from the Halting Problems research note. It does not
contact the network and does not execute target artifacts.
"""
from __future__ import annotations
import argparse
import json
import os
from pathlib import Path
CVE_ID = 'CVE-2026-48282'
VENDOR = 'Adobe'
PRODUCT = 'ColdFusion'
VULNERABILITY_NAME = 'Adobe ColdFusion Path Traversal Vulnerability'
SOURCE_DOMAINS = ['www.cisa.gov', 'helpx.adobe.com', 'nvd.nist.gov']
AFFECTED_VERSION_RANGE = 'ColdFusion 2025 Update 9, ColdFusion 2023 Update 20, and earlier ColdFusion 2025/2023 updates'
FIXED_VERSION = 'ColdFusion 2025 Update 10 or later and ColdFusion 2023 Update 21 or later'
PACKAGE_COORDINATE = 'adobe:coldfusion'
SOURCE_URLS = ['https://www.cisa.gov/known-exploited-vulnerabilities-catalog?field_cve=cve-2026-48282', 'https://helpx.adobe.com/security/products/coldfusion/apsb26-68.html', 'https://www.cisa.gov/news-events/directives/bod-26-04-prioritizing-security-updates-based-risk', 'https://www.cisa.gov/news-events/directives/bod-26-04-implementation-guidance-prioritizing-security-updates-based-risk', 'https://nvd.nist.gov/vuln/detail/CVE-2026-48282']
PRODUCT_MARKERS = ['CVE-2026-48282', 'Adobe', 'ColdFusion', 'Adobe ColdFusion Path Traversal Vulnerability']
OUT_DEFAULT = "hp-adobe-coldfusion-cve-2026-48282-kev-scope"
TEXT_EXTENSIONS = {".txt", ".log", ".json", ".jsonl", ".csv", ".tsv", ".yaml", ".yml", ".xml", ".html", ".md"}
def iter_files(root: Path):
exclude_dirs = {".git", "node_modules", "vendor", "dist", "build", ".venv", "__pycache__"}
for current, dirs, files in os.walk(root):
dirs[:] = [d for d in dirs if d not in exclude_dirs]
for name in files:
path = Path(current) / name
if path.suffix.lower() in TEXT_EXTENSIONS or path.stat().st_size < 2_000_000:
yield path
def read_text(path: Path) -> str:
try:
return path.read_text(encoding="utf-8", errors="ignore")
except OSError:
return ""
def main() -> int:
parser = argparse.ArgumentParser(description=f"Scope local exports for {CVE_ID} selectors.")
parser.add_argument("root", nargs="?", default=".", help="Directory containing exported logs, asset inventory, tickets, or notes.")
parser.add_argument("--out", default=OUT_DEFAULT, help="Output directory for report.json and matched files list.")
args = parser.parse_args()
root = Path(args.root).resolve()
out = Path(args.out).resolve()
out.mkdir(parents=True, exist_ok=True)
indicators = set()
for group in (SOURCE_DOMAINS, SOURCE_URLS, PRODUCT_MARKERS, [AFFECTED_VERSION_RANGE, FIXED_VERSION, PACKAGE_COORDINATE]):
for val in group:
if val:
indicators.add(str(val))
hits = []
for path in iter_files(root):
text = read_text(path)
lower = text.lower()
matched = sorted(ind for ind in indicators if ind.lower() in lower)
if matched:
hits.append({"path": str(path.relative_to(root)), "selectors": matched})
report = {
"event": {"cve_id": CVE_ID, "vendor": VENDOR, "product": PRODUCT, "vulnerability_name": VULNERABILITY_NAME, "package": PACKAGE_COORDINATE, "affected": AFFECTED_VERSION_RANGE, "fixed": FIXED_VERSION},
"scan_root": str(root),
"files_with_hits": len(hits),
"hits": hits,
"interpretation": {
"positive": bool(hits),
"positive_signal": "At least one exported record references the CVE, product, vendor advisory, CISA KEV, or NVD selector.",
"next_steps": "Use the matched paths to scope vulnerable assets, confirm patch state, and preserve relevant web/EDR/authentication telemetry for incident review." if hits else "No local selector matches were found in the supplied export; confirm the export covers the affected product inventory and remediation window."
}
}
(out / "report.json").write_text(json.dumps(report, indent=2), encoding="utf-8")
matched_text = "\n".join(hit["path"] for hit in hits) + ("\n" if hits else "")
(out / "matched_files.txt").write_text(matched_text, encoding="utf-8")
print(json.dumps({"cve_id": CVE_ID, "files_with_hits": len(hits), "report": str(out / "report.json")}, indent=2))
return 1 if False else 0
if __name__ == "__main__":
raise SystemExit(main())