From c7ee0dfcfd267d2d78a91319c31c8a1541697d1f Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 4 Mar 2026 16:21:48 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[CRITICAL]?= =?UTF-8?q?=20Fix=20path=20traversal=20in=20pathHelpers.js?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: PrakharMNNIT <73683289+PrakharMNNIT@users.noreply.github.com> --- src/js/utils/pathHelpers.js | 15 ++++++++++++++- tests/unit/services/LinkNavigationService.test.js | 2 ++ tests/unit/utils/pathHelpers.test.js | 5 +---- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/js/utils/pathHelpers.js b/src/js/utils/pathHelpers.js index ecf0a26..1eb3b37 100644 --- a/src/js/utils/pathHelpers.js +++ b/src/js/utils/pathHelpers.js @@ -55,10 +55,23 @@ export function resolveRelativePath(basePath, relativePath) { export function normalizePath(path) { if (!path) return ''; - return path + const cleanPath = path .replace(/\\/g, '/') // Convert backslashes to forward slashes .replace(/\/+/g, '/') // Collapse multiple slashes .replace(/^\/|\/$/g, ''); // Remove leading/trailing slashes + + const segments = cleanPath.split('/'); + const stack = []; + + for (const segment of segments) { + if (segment === '..') { + stack.pop(); + } else if (segment !== '.' && segment !== '') { + stack.push(segment); + } + } + + return stack.join('/'); } /** diff --git a/tests/unit/services/LinkNavigationService.test.js b/tests/unit/services/LinkNavigationService.test.js index 7409590..42f0480 100644 --- a/tests/unit/services/LinkNavigationService.test.js +++ b/tests/unit/services/LinkNavigationService.test.js @@ -224,6 +224,7 @@ describe('LinkNavigationService', () => { name: 'test.md', path: 'docs/test.md', handle: mockFileHandle, + anchor: null, }); }); @@ -253,6 +254,7 @@ describe('LinkNavigationService', () => { name: 'test.md', path: 'docs/test.md', handle: mockFileHandle, + anchor: null, }); }); diff --git a/tests/unit/utils/pathHelpers.test.js b/tests/unit/utils/pathHelpers.test.js index 47b7122..7445736 100644 --- a/tests/unit/utils/pathHelpers.test.js +++ b/tests/unit/utils/pathHelpers.test.js @@ -236,10 +236,7 @@ describe('pathHelpers', () => { }); it('should handle normalized paths that resolve outside root', () => { - // Normalization converts 'docs/../secret' to 'secret' - // The implementation normalizes the path but doesn't prevent paths that resolved outside root - // It only checks if the normalized path starts with '..' or is empty - expect(isWithinRoot('docs/../secret', 'docs')).toBe(true); // 'secret' is valid normalized path + expect(isWithinRoot('docs/../secret', 'docs')).toBe(false); }); it('should allow nested paths within root', () => {