diff --git a/gitnexus/src/storage/git.ts b/gitnexus/src/storage/git.ts index 9dafa0aee..75e6e91d3 100644 --- a/gitnexus/src/storage/git.ts +++ b/gitnexus/src/storage/git.ts @@ -273,7 +273,7 @@ export const sanitizeRepoName = (name: string): string => { // 3. Block path traversal segments and Windows reserved names. // Windows reserved names like CON, PRN, AUX, NUL, COM1-9, LPT1-9 cannot // be used as directory names on Windows even if they have an extension. - const reserved = /^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$/i; + const reserved = /^(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])(\..*)?$/i; if (!sanitized || sanitized === '.' || sanitized === '..' || reserved.test(sanitized)) { return 'unknown'; } diff --git a/gitnexus/test/unit/git.test.ts b/gitnexus/test/unit/git.test.ts index 41f66bc61..1bebf4143 100644 --- a/gitnexus/test/unit/git.test.ts +++ b/gitnexus/test/unit/git.test.ts @@ -190,6 +190,11 @@ describe('git utilities', () => { expect(sanitizeRepoName('NUL')).toBe('unknown'); expect(sanitizeRepoName('COM1')).toBe('unknown'); expect(sanitizeRepoName('LPT9')).toBe('unknown'); + + // Reserved names with extensions + expect(sanitizeRepoName('CON.txt')).toBe('unknown'); + expect(sanitizeRepoName('NUL.tar.gz')).toBe('unknown'); + expect(sanitizeRepoName('AUX.local')).toBe('unknown'); }); it('returns unknown for empty or invalid input', () => {