From 59cf654b658c80420eaeb3cf11a1be16ddd1c7ed Mon Sep 17 00:00:00 2001 From: gonzaloriestra <14979109+gonzaloriestra@users.noreply.github.com> Date: Fri, 15 May 2026 00:49:03 +0000 Subject: [PATCH 1/2] [Security] Prevent absolute path bypass in sanitizeRelativePath Enhance sanitizeRelativePath to strip leading slashes and Windows drive letters, ensuring paths are strictly relative. Add unit tests to verify cross-platform safety. --- packages/cli-kit/src/public/node/path.test.ts | 28 +++++++++++++++++-- packages/cli-kit/src/public/node/path.ts | 12 ++++++-- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/packages/cli-kit/src/public/node/path.test.ts b/packages/cli-kit/src/public/node/path.test.ts index 4972b3ac276..1cb801b5a9e 100644 --- a/packages/cli-kit/src/public/node/path.test.ts +++ b/packages/cli-kit/src/public/node/path.test.ts @@ -1,5 +1,5 @@ -import {relativizePath, normalizePath, cwd, sniffForPath, commonParentDirectory} from './path.js' -import {describe, test, expect} from 'vitest' +import {relativizePath, normalizePath, cwd, sniffForPath, commonParentDirectory, sanitizeRelativePath} from './path.js' +import {describe, test, expect, vi} from 'vitest' describe('relativize', () => { test('relativizes the path', () => { @@ -93,3 +93,27 @@ describe('sniffForPath', () => { expect(path).toStrictEqual('/path/to/project') }) }) + +describe('sanitizeRelativePath', () => { + test('returns the path if it is relative and has no traversal', () => { + // Given + const path = 'some/path' + const warn = vi.fn() + + // When + const got = sanitizeRelativePath(path, warn) + + // Then + expect(got).toBe('some/path') + expect(warn).not.toHaveBeenCalled() + }) + + test('strips traversal and absolute path segments and warns', () => { + const warn = vi.fn() + expect(sanitizeRelativePath('some/../path', warn)).toBe('path') + expect(sanitizeRelativePath('/etc/passwd', warn)).toBe('etc/passwd') + expect(sanitizeRelativePath('\\some\\path', warn)).toBe('some/path') + expect(sanitizeRelativePath('C:\\Windows', warn)).toBe('Windows') + expect(warn).toHaveBeenCalledTimes(4) + }) +}) diff --git a/packages/cli-kit/src/public/node/path.ts b/packages/cli-kit/src/public/node/path.ts index f3721780110..c29b4d94c15 100644 --- a/packages/cli-kit/src/public/node/path.ts +++ b/packages/cli-kit/src/public/node/path.ts @@ -217,20 +217,26 @@ export function sniffForJson(argv = process.argv): boolean { * @returns The sanitized path (may be an empty string if all segments were traversal). */ export function sanitizeRelativePath(input: string, warn: (msg: string) => void): string { - const segments = input.replace(/\\/g, '/').split('/') + const normalized = input.replace(/\\/g, '/') + const segments = normalized.split('/') const stack: string[] = [] let stripped = false + + if (normalized.startsWith('/') || /^[a-zA-Z]:/.test(normalized)) { + stripped = true + } + for (const seg of segments) { if (seg === '..') { stripped = true stack.pop() - } else if (seg !== '.') { + } else if (seg !== '.' && seg !== '' && !/^[a-zA-Z]:$/.test(seg)) { stack.push(seg) } } const result = stack.join('/') if (stripped) { - warn(`Warning: path '${input}' contains '..' traversal — sanitized to '${result || '.'}'\n`) + warn(`Warning: path '${input}' is insecure (contains '..' or is absolute) — sanitized to '${result || '.'}'\n`) } return result } From d961a006c9e45c75685bfae7f796fb4bfcb4e4be Mon Sep 17 00:00:00 2001 From: gonzaloriestra <14979109+gonzaloriestra@users.noreply.github.com> Date: Fri, 15 May 2026 01:14:03 +0000 Subject: [PATCH 2/2] [Security] Prevent absolute path bypass in sanitizeRelativePath Enhance sanitizeRelativePath to strip leading slashes and Windows drive letters, ensuring paths are strictly relative and cross-platform safe. Improve warning messages to accurately describe the security risk. Add unit tests for various traversal and absolute path scenarios.