From e706f6b05645601632c1c142c0af35c80101f3f4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 16 Jan 2026 21:02:30 +0000 Subject: [PATCH 1/3] Initial plan From 4a958eb9b9e1956bf86c7946290096adb01b14ca Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 16 Jan 2026 21:05:53 +0000 Subject: [PATCH 2/3] Fix security vulnerability in setup.ts path validation - Import path.resolve() and path.sep for robust validation - Use resolve() to get absolute paths and verify within project - Check that resolved path is within ROOT_DIR using startsWith() - Verify exact match to node_modules folder to prevent path traversal - Replace weak endsWith() check with secure path resolution Co-authored-by: toolate28 <105518313+toolate28@users.noreply.github.com> --- scripts/setup.ts | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/scripts/setup.ts b/scripts/setup.ts index ae2617d..3c1239d 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, sep } from "path"; const ROOT_DIR = join(import.meta.dir, ".."); const ATOM_TRAIL_DIR = join(ROOT_DIR, ".atom-trail"); @@ -101,8 +101,18 @@ 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); + + // Check that the path is within the project directory + // and specifically points to the node_modules folder + const isWithinProject = + resolvedNodeModules.startsWith(resolvedRoot + sep) && + resolvedNodeModules === join(resolvedRoot, "node_modules"); + + if (existsSync(nodeModulesPath) && isWithinProject) { rmSync(nodeModulesPath, { recursive: true, force: true }); } await $`cd ${ROOT_DIR} && bun install`.quiet(); From ee399d2a14e023675f639016e90ef6d825ad858e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 16 Jan 2026 21:07:01 +0000 Subject: [PATCH 3/3] Simplify path validation logic to handle edge cases - Use exact path matching instead of startsWith() check - Compare resolved paths directly using resolve() for both paths - Remove unused sep import - Handles all platforms correctly including Windows root drives - More secure and simpler to understand Co-authored-by: toolate28 <105518313+toolate28@users.noreply.github.com> --- scripts/setup.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/scripts/setup.ts b/scripts/setup.ts index 3c1239d..d174521 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, resolve, sep } from "path"; +import { join, resolve } from "path"; const ROOT_DIR = join(import.meta.dir, ".."); const ATOM_TRAIL_DIR = join(ROOT_DIR, ".atom-trail"); @@ -105,14 +105,13 @@ async function installDependencies(force: boolean): Promise { // 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 path is within the project directory - // and specifically points to the node_modules folder - const isWithinProject = - resolvedNodeModules.startsWith(resolvedRoot + sep) && - resolvedNodeModules === join(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) && isWithinProject) { + if (existsSync(nodeModulesPath) && isValidPath) { rmSync(nodeModulesPath, { recursive: true, force: true }); } await $`cd ${ROOT_DIR} && bun install`.quiet();