flawopen.com/Path Traversal/Node path.join()
Does Node.js path.join() prevent path traversal?
No. path.join() normalizes path segments, but it does not stop .. from escaping an intended directory. Resolve the candidate against the base directory, then verify that the relative path stays inside the base. This lexical check does not by itself contain filesystem symlinks.
const filePath = path.join( BASE_DIR, userFilename ); // userFilename = "../../etc/passwd" // still escapes BASE_DIR
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");
}
Why path.join() alone does not help
path.join() combines path segments with the platform-specific separator and normalizes the result. Normalization does not reject .., which is valid in many paths. Joining ../../etc/passwd to a base can still produce a path outside that base; join() is not a containment check.
FAQ
path.normalize() resolves .. and . segments in the string, but it does not verify containment within an allowed base. Compare path.relative(base, resolved) and reject an empty result when a file is required, .., a value starting with .. plus path.sep, or an absolute relative result.
No. path.resolve() and path.relative() compare path strings; they do not follow filesystem symlinks. If an attacker can create or replace symlinks under the base, validate the resolved filesystem target and use filesystem access patterns that prevent a check/use race. Restrict write access to the tree when possible.