FlawOpen

flawopen.com/Path Traversal/Node.js path.join()

¿Node.js path.join() evita Path Traversal?

Página de referencia
Respuesta breve

No. path.join() normaliza los segmentos, pero no impide que .. salga del directorio previsto. Resuelve la ruta candidata con respecto a la base y verifica que la ruta relativa permanezca dentro. Esta comprobación léxica no contiene los symlinks del sistema de archivos.

SIGUE SIENDO VULNERABLE
const filePath = path.join(
  BASE_DIR, userFilename
);
// userFilename = "../../etc/passwd"
// still escapes BASE_DIR
CORREGIDO — comprobación léxica de contención
const base = path.resolve(BASE_DIR);
const resolved = path.resolve(base, userFilename);
const relative = path.relative(base, resolved);

if (
  relative === '' ||
  relative === '..' ||
  relative.startsWith('..' + path.sep) ||
  path.isAbsolute(relative)
) {
  throw new Error("Invalid path");
}

Por qué path.join() no basta

path.join() combina segmentos con el separador de la plataforma y normaliza el resultado. La normalización no rechaza .., que es válido en muchas rutas. Unir ../../etc/passwd a una base aún puede producir una ruta externa; join() no verifica la contención.

Preguntas frecuentes

¿Ayuda path.normalize()?

path.normalize() resuelve segmentos .. y . en la cadena, pero no verifica que el resultado permanezca dentro de una base permitida. Compara path.relative(base, resolved) y rechaza un resultado vacío si se requiere un archivo, .., un prefijo .. seguido de path.sep o un resultado relativo absoluto.

¿Esta comprobación evita escapar mediante symlinks?

No. path.resolve() y path.relative() comparan cadenas de ruta; no siguen symlinks del sistema de archivos. Si un atacante puede crear o reemplazar symlinks bajo la base, valida el destino real y usa operaciones que eviten una carrera entre comprobación y uso. Restringe los permisos de escritura del árbol cuando sea posible.

Referencias

Véase también Path traversal (CWE-22): cómo funciona y cómo evitarlo en todos los lenguajes — flawopen.com PHP include() y rutas controladas por el usuario Corregir path traversal con Python os.path.join() ¿Qué es una vulnerabilidad Zip Slip?