#!/usr/bin/env python3
"""Scope CVE-2026-48558 exposure from asset inventories and exported product logs.
Input: a directory containing CSV, JSON, JSONL, TXT, LOG, YAML, or XML exports.
The script does not contact the network. It looks for the CVE, vendor/product
selectors, and affected-version selectors recorded in the Halting Problems profile.
"""
from __future__ import annotations
import csv, json, os, sys
from pathlib import Path
CVE_ID = "CVE-2026-48558"
VENDOR = "SimpleHelp"
PRODUCT = "SimpleHelp"
AFFECTED_VERSION_SELECTORS = [
"simple-help-simplehelp < 5.5.16",
"simple-help-simplehelp@6.0"
]
SOURCE_SELECTORS = [
"https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json",
"https://nvd.nist.gov/vuln/detail/CVE-2026-48558",
"https://horizon3.ai/attack-research/disclosures/cve-2026-48558-simplehelp-authentication-bypass-iocs/",
"https://simple-help.com/release-news",
"https://simple-help.com/security/simplehelp-security-update-2026-05",
"https://blackpointcyber.com/blog/a-djinn-in-the-machine-taskweavers-node-js-intrusion-chain/",
"https://www.cisa.gov/known-exploited-vulnerabilities-catalog?field_cve=CVE-2026-48558"
]
DOMAINS = []
HASHES = []
URLS = []
FILES = []
PROCESS_PATTERNS = [PRODUCT, VENDOR, CVE_ID]
NETWORK_PATTERNS = []
INDICATORS = [
"CVE-2026-48558",
"SimpleHelp",
"SimpleHelp",
"simple-help-simplehelp < 5.5.16",
"simple-help-simplehelp@6.0",
"https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json",
"https://nvd.nist.gov/vuln/detail/CVE-2026-48558",
"https://horizon3.ai/attack-research/disclosures/cve-2026-48558-simplehelp-authentication-bypass-iocs/",
"https://simple-help.com/release-news",
"https://simple-help.com/security/simplehelp-security-update-2026-05",
"https://blackpointcyber.com/blog/a-djinn-in-the-machine-taskweavers-node-js-intrusion-chain/",
"https://www.cisa.gov/known-exploited-vulnerabilities-catalog?field_cve=CVE-2026-48558"
]
OUT = os.environ.get("OUT", "hp-simplehelp-cve-2026-48558-kev-scope")
TEXT_SUFFIXES = {'.csv','.json','.jsonl','.txt','.log','.yaml','.yml','.xml','.conf','.ini','.md'}
EXCLUDED_DIR_NAMES = {'.git','node_modules','vendor','dist','__pycache__','.venv'}
def read_text(path: Path) -> str:
try:
return path.read_text(encoding='utf-8', errors='ignore')
except Exception:
return ''
def iter_files(root: Path):
if root.is_file():
yield root; return
for p in root.rglob('*'):
if p.is_file() and not any(part in EXCLUDED_DIR_NAMES for part in p.parts):
if not p.suffix or p.suffix.lower() in TEXT_SUFFIXES:
yield p
def scan(root: Path):
matches=[]
lowered=[s.lower() for s in INDICATORS if s]
for path in iter_files(root):
text=read_text(path)
low=text.lower()
hits=sorted({INDICATORS[i] for i,s in enumerate(lowered) if s in low})
if hits:
matches.append({'path': str(path), 'hits': hits})
return matches
def main(argv=None):
argv=argv or sys.argv[1:]
root=Path(argv[0]) if argv else Path('.')
matches=scan(root)
out_dir=Path(OUT); out_dir.mkdir(parents=True, exist_ok=True)
report={'cve': CVE_ID, 'vendor': VENDOR, 'product': PRODUCT, 'affected_version_selectors': AFFECTED_VERSION_SELECTORS, 'match_count': len(matches), 'matches': matches}
(out_dir/'scope_report.json').write_text(json.dumps(report, indent=2), encoding='utf-8')
print(json.dumps({'cve': CVE_ID, 'match_count': len(matches), 'report': str(out_dir/'scope_report.json')}, indent=2))
return 2 if matches else 0
if __name__ == '__main__':
raise SystemExit(main())