fix(worker): contain workspace paths against symlinks

This commit is contained in:
Gabriel Brown
2026-07-10 17:11:00 -04:00
parent 2bc090c378
commit 57c175aecd
4 changed files with 107 additions and 23 deletions
+39
View File
@@ -0,0 +1,39 @@
import { lstat, realpath } from 'node:fs/promises';
import path from 'node:path';
const realpathOrDeepestExisting = async (target: string): Promise<string> => {
let current = target;
const tail: string[] = [];
for (;;) {
try {
const real = await realpath(current);
return path.join(real, ...tail.reverse());
} catch (error) {
if ((error as { code?: string }).code !== 'ENOENT') throw error;
const parent = path.dirname(current);
if (parent === current) throw error;
tail.push(path.basename(current));
current = parent;
}
}
};
export const assertContainedRealPath = async (
root: string,
requested: string,
opts: { forWrite?: boolean } = {},
): Promise<string> => {
const lexical = path.resolve(root, requested);
const realRoot = await realpath(root);
const resolved = await realpathOrDeepestExisting(lexical);
if (resolved !== realRoot && !resolved.startsWith(`${realRoot}${path.sep}`)) {
throw new Error(`Refusing to access path outside root: ${requested}`);
}
if (opts.forWrite) {
const info = await lstat(lexical).catch(() => null);
if (info?.isSymbolicLink()) {
throw new Error(`Refusing to write through a symlink: ${requested}`);
}
}
return resolved;
};