fix(desktop): allow double dots in bundle filenames (#5515)

This commit is contained in:
tt-a1i 2026-06-21 06:16:50 +08:00 committed by GitHub
parent 8b6ac721fa
commit ca7638e85c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 24 additions and 1 deletions

View file

@ -72,6 +72,25 @@ describe('bundle-files', () => {
expect(validateBundleFile(file)).toContain('Path traversal')
})
it('rejects parent traversal segments below the bundle root', () => {
const file: BundleFile = {
relativePath: 'docs/../escape.txt',
contentBase64: Buffer.from('x').toString('base64'),
size: 1,
}
expect(validateBundleFile(file)).toContain('Path traversal')
})
it('accepts double dots inside a path segment', () => {
const content = Buffer.from('hello')
const file: BundleFile = {
relativePath: 'docs/release..notes.md',
contentBase64: content.toString('base64'),
size: content.length,
}
expect(validateBundleFile(file)).toBeNull()
})
it('rejects absolute paths', () => {
const file: BundleFile = {
relativePath: '/etc/passwd',

View file

@ -47,6 +47,10 @@ export function fromPortableRelPath(portablePath: string): string {
return portablePath.split('/').join(sep)
}
function hasParentTraversalSegment(portablePath: string): boolean {
return portablePath.split('/').includes('..')
}
// ============================================================
// Validation
// ============================================================
@ -61,7 +65,7 @@ export function validateBundleFile(file: BundleFile): string | null {
}
// Path traversal checks
if (file.relativePath.includes('..')) {
if (hasParentTraversalSegment(file.relativePath)) {
return `Path traversal detected: ${file.relativePath}`
}
if (file.relativePath.startsWith('/') || file.relativePath.startsWith('\\')) {