diff --git a/scripts/setup.ts b/scripts/setup.ts index 56e5aeb..d1195b2 100644 --- a/scripts/setup.ts +++ b/scripts/setup.ts @@ -15,7 +15,7 @@ import { $ } from "bun"; import { existsSync, rmSync } from "fs"; import { mkdir, writeFile } from "fs/promises"; -import { join } from "path"; +import { join, resolve } from "path"; const ROOT_DIR = join(import.meta.dir, ".."); const ATOM_TRAIL_DIR = join(ROOT_DIR, ".atom-trail"); @@ -101,8 +101,17 @@ async function installDependencies(force: boolean): Promise { const nodeModulesPath = join(ROOT_DIR, "node_modules"); if (force) { log("step", "Force reinstalling dependencies..."); - // Validate path before removal for safety - if (existsSync(nodeModulesPath) && nodeModulesPath.endsWith("node_modules")) { + // Validate path before removal for security + // Ensure the resolved path is within the project directory + const resolvedNodeModules = resolve(nodeModulesPath); + const resolvedRoot = resolve(ROOT_DIR); + const expectedPath = resolve(resolvedRoot, "node_modules"); + + // Check that the resolved path exactly matches the expected node_modules path + // This prevents path traversal attacks (e.g., /etc/node_modules) + const isValidPath = resolvedNodeModules === expectedPath; + + if (existsSync(nodeModulesPath) && isValidPath) { rmSync(nodeModulesPath, { recursive: true, force: true }); } await $`cd ${ROOT_DIR} && bun install`.quiet();