Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/filesystem/__tests__/path-validation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
});
});
20 changes: 18 additions & 2 deletions src/filesystem/path-validation.ts
Original file line number Diff line number Diff line change
@@ -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.
*
Expand Down Expand Up @@ -27,14 +43,14 @@
// Normalize the input path
let normalizedPath: string;
try {
normalizedPath = path.resolve(path.normalize(absolutePath));
normalizedPath = safeNormalize(absolutePath);
} catch {
return false;
}

// Verify it's absolute after normalization
if (!path.isAbsolute(normalizedPath)) {
throw new Error('Path must be absolute after normalization');

Check failure on line 53 in src/filesystem/path-validation.ts

View workflow job for this annotation

GitHub Actions / Test filesystem

__tests__/path-validation.test.ts > Path Validation > UNC paths (Windows network shares) > should accept the UNC directory itself

Error: Path must be absolute after normalization ❯ Module.isPathWithinAllowedDirectories path-validation.ts:53:11 ❯ __tests__/path-validation.test.ts:1017:14

Check failure on line 53 in src/filesystem/path-validation.ts

View workflow job for this annotation

GitHub Actions / Test filesystem

__tests__/path-validation.test.ts > Path Validation > UNC paths (Windows network shares) > should reject files outside a UNC allowed directory

Error: Path must be absolute after normalization ❯ Module.isPathWithinAllowedDirectories path-validation.ts:53:11 ❯ __tests__/path-validation.test.ts:1011:14

Check failure on line 53 in src/filesystem/path-validation.ts

View workflow job for this annotation

GitHub Actions / Test filesystem

__tests__/path-validation.test.ts > Path Validation > UNC paths (Windows network shares) > should accept files within a UNC allowed directory

Error: Path must be absolute after normalization ❯ Module.isPathWithinAllowedDirectories path-validation.ts:53:11 ❯ __tests__/path-validation.test.ts:1005:14
}

// Check against each allowed directory
Expand All @@ -51,7 +67,7 @@
// Normalize the allowed directory
let normalizedDir: string;
try {
normalizedDir = path.resolve(path.normalize(dir));
normalizedDir = safeNormalize(dir);
} catch {
return false;
}
Expand Down
Loading