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
+4 -11
View File
@@ -7,6 +7,7 @@ import type { Id } from '@spoon/backend/convex/_generated/dataModel.js';
import { api } from '@spoon/backend/convex/_generated/api.js';
import { env } from './env';
import { assertContainedRealPath } from './path-containment';
import { runExecInContainer } from './runtime/docker';
const client = new ConvexHttpClient(env.convexUrl);
@@ -31,16 +32,6 @@ export const fetchUserEnvironment = async (
const shellQuote = (value: string) => `'${value.replaceAll("'", "'\\''")}'`;
// Keep a written path inside the home directory.
const safeHomeJoin = (homeDir: string, relPath: string) => {
const target = path.resolve(homeDir, relPath);
const root = path.resolve(homeDir);
if (target !== root && !target.startsWith(`${root}${path.sep}`)) {
throw new Error(`Refusing to write dotfile outside home: ${relPath}`);
}
return target;
};
/**
* Materializes the persistent per-user home: a `.bash_profile` so login shells
* load `~/.bashrc`; (when configured and changed) a clone of the public dotfiles
@@ -111,7 +102,9 @@ export const materializeUserHome = async (args: {
// Editable overlay tree (wins over the repo/setup output).
for (const file of userEnv.files) {
const target = safeHomeJoin(homeDir, file.path);
const target = await assertContainedRealPath(homeDir, file.path, {
forWrite: true,
});
await mkdir(path.dirname(target), { recursive: true });
await writeFile(target, file.content);
if (file.isExecutable) await chmod(target, 0o755);