diff --git a/src/filesystem/__tests__/path-validation.test.ts b/src/filesystem/__tests__/path-validation.test.ts index 81ad247ee2..a64b14b629 100644 --- a/src/filesystem/__tests__/path-validation.test.ts +++ b/src/filesystem/__tests__/path-validation.test.ts @@ -997,4 +997,24 @@ describe('Path Validation', () => { expect(forbiddenContent).toBe('ORIGINAL CONTENT'); // Unchanged }); }); + + describe('UNC paths (Windows network shares)', () => { + // UNC path tests use string-only checks (no filesystem access needed) + it('should accept files within a UNC allowed directory', () => { + const allowed = ['\\\\server\\share']; + expect(isPathWithinAllowedDirectories('\\\\server\\share\\file.txt', allowed)).toBe(true); + expect(isPathWithinAllowedDirectories('\\\\server\\share\\sub\\deep.txt', allowed)).toBe(true); + }); + + it('should reject files outside a UNC allowed directory', () => { + const allowed = ['\\\\server\\share']; + expect(isPathWithinAllowedDirectories('\\\\server\\other\\file.txt', allowed)).toBe(false); + expect(isPathWithinAllowedDirectories('\\\\other-server\\share\\file.txt', allowed)).toBe(false); + }); + + it('should accept the UNC directory itself', () => { + const allowed = ['\\\\server\\share']; + expect(isPathWithinAllowedDirectories('\\\\server\\share', allowed)).toBe(true); + }); + }); }); diff --git a/src/filesystem/path-validation.ts b/src/filesystem/path-validation.ts index 972e9c49d0..83e4c38ac2 100644 --- a/src/filesystem/path-validation.ts +++ b/src/filesystem/path-validation.ts @@ -1,5 +1,21 @@ import path from 'path'; +/** + * Normalize a path, preserving UNC prefix on Windows. + * path.normalize can strip one leading backslash from UNC paths + * (e.g. \\\\server\\share → \\server\\share), and path.resolve then + * misinterprets the single-backslash path as drive-relative. + */ +function safeNormalize(p: string): string { + const isUNC = p.startsWith('\\\\'); + let normalized = path.resolve(path.normalize(p)); + // If the original was a UNC path but normalization lost the prefix, restore it + if (isUNC && !normalized.startsWith('\\\\')) { + normalized = '\\' + normalized; + } + return normalized; +} + /** * Checks if an absolute path is within any of the allowed directories. * @@ -27,7 +43,7 @@ export function isPathWithinAllowedDirectories(absolutePath: string, allowedDire // Normalize the input path let normalizedPath: string; try { - normalizedPath = path.resolve(path.normalize(absolutePath)); + normalizedPath = safeNormalize(absolutePath); } catch { return false; } @@ -51,7 +67,7 @@ export function isPathWithinAllowedDirectories(absolutePath: string, allowedDire // Normalize the allowed directory let normalizedDir: string; try { - normalizedDir = path.resolve(path.normalize(dir)); + normalizedDir = safeNormalize(dir); } catch { return false; }