Safe Path Join Blocking Traversal
A path resolver that joins untrusted segments onto a base directory and rejects any attempt to escape it via dot dot segments or absolute paths.
Code
import { isAbsolute, join, normalize, resolve, sep } from "node:path";
export class PathTraversalError extends Error {
constructor(message: string) {
super(message);
this.name = "PathTraversalError";
}
}
/**
* Resolve untrusted segments against a base directory, refusing any escape.
* Containment is verified with an explicit prefix check after normalization. */
export function safeJoin(baseDir: string, ...segments: string[]): string {
const base = resolve(baseDir);
for (const segment of segments) {
if (typeof segment !== "string" || segment.length === 0) {
throw new PathTraversalError("path segments must be non-empty strings");
}
if (isAbsolute(segment)) {
throw new PathTraversalError("absolute path segments are not allowed: " + segment);
}
}
const target = normalize(join(base, ...segments));
if (target !== base && !target.startsWith(base + sep)) {
throw new PathTraversalError("resolved path escapes the base directory: " + target);
}
return target;
}Report a problem with this exampleOpens a pre-filled issue on GitHub.