
Documenta CVE-2026-65320, un path traversal de tipo tar-slip en untar_dir() de fastcore, con una prueba de concepto inofensiva que demuestra escritura arbitraria de archivos y ejecución de código.
untar_dir()Severidad: Crítica, CVSS 3.1 9.8
Vector (v3.1): CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
Afecta a: fastcore <= 2.2.30
Corregido en: No corregido en el momento de redacción
CWE: CWE-22 (Limitación incorrecta de un nombre de ruta a un directorio restringido, 'Path Traversal')
Componente: fastcore.xtras.untar_dir() → fastcore.xtras._unpack() → shutil.unpack_archive()
Entorno de ejecución de alto riesgo: Python < 3.14 (Python 3.14 hace que el filtro tar seguro data sea el predeterminado)
Reportado por: Rahul Karne
CNA: VulnCheck
fastcore.xtras.untar_dir(fname, dest) es un helper documentado que descomprime un archivo tar "en dest".
Internamente, entrega el archivo a shutil.unpack_archive() de la biblioteca estándar sin un filtro de extracción, sin validar las rutas de los miembros del archivo y sin ninguna comprobación de contención posterior a la extracción.
Como resultado, un archivo TAR cuyos miembros contienen secuencias de traversal ../ o rutas absolutas puede escribir archivos fuera del directorio en el que el llamador pidió a fastcore que extrajera.
Un llamador que razonablemente espera que untar_dir(fname, dest) confine todo a dest en su lugar obtiene escritura arbitraria de archivos en cualquier lugar donde el proceso pueda escribir.
Escritura arbitraria de archivos bajo la autoridad del proceso que llama a untar_dir().
Dependiendo de lo que se sobrescriba, esto puede dar lugar a:
La prueba de concepto demuestra la cadena completa escritura → importación → ejecución de código de principio a fin, enteramente dentro de un directorio de demostración inofensivo.
fastcore es una dependencia fundamental en todo el ecosistema fast.ai, incluyendo:
fastainbdevghapiRecibe decenas de millones de descargas al mes.
untar_dir() es la primitiva de extracción detrás del flujo de trabajo común "descargar un archivo, luego descomprimirlo", que sigue el mismo patrón general que untar_data de fastai.
Cualquier ruta de código que alimente a untar_dir() con un archivo cuyo contenido no sea totalmente confiable queda expuesta.
El código vulnerable existe en fastcore/xtras.py:
def _unpack(fname, out):
import shutil
shutil.unpack_archive(str(fname), str(out)) # <-- no filter, no validation
ls = out.ls()
return ls[0] if len(ls) == 1 else out
def untar_dir(fname, dest, rename=False, overwrite=False, uid=-1, gid=-1):
"untar `file` into `dest` ..."
import tempfile, shutil
dest = Path(dest)
with tempfile.TemporaryDirectory() as d:
out = Path(d) / remove_suffix(Path(fname).stem, '.tar')
out.mkdir()
...
src = _unpack(fname, out) # extraction escapes `out` here
...
shutil.move(str(src), dest)
...
return dest
untar_dir() crea un directorio temporal interno de extracción:
<tempdir>/<random>/<archive-stem>/
Luego llama a _unpack(), que reenvía el archivo directamente a:
shutil.unpack_archive()
Para archivos TAR, esto finalmente llama a tarfile.extractall().
En Python < 3.14, el comportamiento de extracción predeterminado es fully_trusted, lo que significa que los miembros con traversal pueden ser aceptados.
Por ejemplo, un miembro del archivo como:
../../../some/other/dir/file
se escribe en relación con el directorio de extracción y, por lo tanto, puede escapar de él.
Nada en fastcore:
filter="data" donde es compatible....untar_dir() trata a shutil.unpack_archive() como si fuera un extractor de archivos seguro y en sandbox.
No lo es.
La documentación de la biblioteca estándar de Python advierte que extraer archivos no confiables puede crear archivos fuera del destino solicitado y recomienda un filtrado de extracción seguro para archivos TAR.
fastcore ni pasa un filtro de extracción apropiado ni implementa una protección de contención equivalente para las versiones de Python que soporta.
Tampoco advierte a los llamadores de untar_dir() sobre este comportamiento sensible a la seguridad.
Los miembros TAR pueden contener cadenas de ruta arbitrarias.
En las versiones de Python afectadas, tarfile.extractall() no neutraliza automáticamente las secuencias de traversal .. de forma predeterminada.
Escribir un miembro con traversal en relación con el directorio temporal de extracción de fastcore es, por lo tanto, suficiente para escapar de ese directorio y escribir en cualquier lugar donde el proceso tenga permiso de escritura.
Una primitiva fiable es el traversal relativo como:
../../../target/file
Esta es la técnica utilizada por la prueba de concepto.
La entrada peligrosa es el contenido del archivo, no la ruta de destino elegida por el desarrollador.
Los archivos se obtienen con frecuencia de ubicaciones externas o semiconfiables, incluyendo:
Cualquier servicio o herramienta que descargue un archivo de una fuente no confiable o semiconfiable y posteriormente lo procese usando untar_dir() puede, por lo tanto, ser alcanzable.
La PoC también incluye una variante que sirve el archivo manipulado desde un endpoint HTTP controlado por el atacante para demostrar esta ruta de entrega.
La explotación exitosa requiere:
La aplicación llama a fastcore.xtras.untar_dir() sobre un archivo cuyo contenido está influenciado por el atacante, como un archivo subido, descargado o de otro modo no confiable.
El entorno de ejecución usa Python < 3.14, u otra configuración donde no se aplique un filtro de extracción TAR seguro.
Para la escalada de escritura arbitraria de archivos a ejecución de código, el proceso posteriormente importa o carga un archivo desde una ubicación alcanzable por el traversal, como:
La escritura arbitraria de archivos y la modificación de configuración/datos requieren solo las condiciones 1 y 2.
poc_fastcore_cna_demo.py invoca la API real fastcore.xtras.untar_dir().
La demostración es intencionadamente inofensiva.
Cada archivo creado por la PoC permanece dentro de un único directorio de demostración especificado usando:
--demo-root
La PoC no modifica archivos reales del sistema y no accede a servicios en la nube ni a credenciales.
_unpack() y untar_dir().