You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
fix(filesystem): normalizePath returns 'C:.' for bare Windows drive letters #3418
normalizePath('C:') returns C:. instead of C:\ on Windows. This can break path validation when fs.realpath() returns a bare drive letter without a trailing separator.
This happens because path.normalize('C:') returns C:. (current directory on the C: drive), and normalizePath doesn't account for this edge case.
Impact
When a user configures a drive root (e.g., D:\) as an allowed directory, fs.realpath() may return the path without a trailing separator. This flows through normalizePath → C:. → path validation fails → "access denied" even though the path should be allowed.
Originally reported in PR #1709 (now closed due to stale conflicts), with screenshot evidence of the bug in production.
Suggested Fix
Handle bare drive letters in normalizePath() in path-utils.ts — detect the X: pattern (single letter + colon, no path after) and append path.sep before normalizing:
// In normalizePath(), before path.normalize():if(process.platform==='win32'&&/^[a-zA-Z]:$/.test(p)){p=p+path.sep;}
Confirmed — this is a classic Windows path edge case that bites a lot of Node.js code.
Why path.normalize('C:') returns C:.:
On Windows, C: means "current directory on the C: drive" (relative), while C:\ means "root of C: drive" (absolute). Node's path.normalize faithfully returns C:. because that's technically the correct normalized form of "current directory on C:".
The fix looks correct. One minor suggestion — also handle lowercase drive letters and the edge case where someone passes C: with a trailing backslash that gets stripped elsewhere:
functionnormalizePath(p: string): string{// Windows: bare drive letters need trailing separator before normalize()if(process.platform==='win32'){// Match 'C:' or 'c:' (no path component after)if(/^[a-zA-Z]:$/.test(p)){p=p+path.sep;}}returnpath.normalize(p);}
Test cases to add:
// Windows bare drive lettersexpect(normalizePath('C:')).toBe('C:\\');expect(normalizePath('d:')).toBe('d:\\');// lowercase// These should still workexpect(normalizePath('C:\\')).toBe('C:\\');expect(normalizePath('C:/')).toBe('C:\\');expect(normalizePath('C:\\Users')).toBe('C:\\Users');
Activity
xXMrNidaXx commentedon Feb 28, 2026
Confirmed — this is a classic Windows path edge case that bites a lot of Node.js code.
Why
path.normalize('C:')returnsC:.:On Windows,
C:means "current directory on the C: drive" (relative), whileC:\means "root of C: drive" (absolute). Node'spath.normalizefaithfully returnsC:.because that's technically the correct normalized form of "current directory on C:".The fix looks correct. One minor suggestion — also handle lowercase drive letters and the edge case where someone passes
C:with a trailing backslash that gets stripped elsewhere:Test cases to add:
Happy to review a PR if this moves forward.
fix(filesystem): ensure bare Windows drive letters normalize to root
fix(filesystem): ensure bare Windows drive letters normalize to root (#…