FlawOpen

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

Node.js path.join() impede Path Traversal?

Página de referência
Resposta curta

Não. path.join() normaliza segmentos, mas não impede que .. saia do diretório pretendido. Resolva o caminho candidato em relação à base e confirme que o caminho relativo permanece dentro dela. Essa verificação lexical não contém symlinks do sistema de arquivos.

AINDA VULNERÁVEL
const filePath = path.join(
  BASE_DIR, userFilename
);
// userFilename = "../../etc/passwd"
// still escapes BASE_DIR
CORRIGIDO — verificação lexical de contenção
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 que path.join() sozinho não ajuda

path.join() combina segmentos com o separador da plataforma e normaliza o resultado. A normalização não rejeita .., que é válido em muitos caminhos. Juntar ../../etc/passwd a uma base ainda pode produzir um caminho fora dela; join() não verifica contenção.

Perguntas frequentes

path.normalize() ajuda?

path.normalize() resolve segmentos .. e . na string, mas não verifica se o resultado está dentro de uma base permitida. Compare path.relative(base, resolved) e rejeite resultado vazio quando um arquivo é obrigatório, .., prefixo .. seguido de path.sep ou resultado relativo absoluto.

Essa verificação impede escapes por symlink?

Não. path.resolve() e path.relative() comparam strings; não seguem symlinks do sistema de arquivos. Se um atacante puder criar ou substituir symlinks sob a base, valide o destino real e use operações que evitem uma corrida entre verificação e uso. Restrinja escrita na árvore quando possível.

Referências

Veja também Path traversal (CWE-22): como funciona e como evitar em todas as linguagens — flawopen.com PHP include() e caminhos controlados pelo usuário Correção de path traversal em Python os.path.join() O que é uma vulnerabilidade Zip Slip?