From 7668f6ae9cca0a0dbb525a8c565a9b90adbe6e0f Mon Sep 17 00:00:00 2001 From: LuoPengcheng <2653972504@qq.com> Date: Wed, 28 Jan 2026 19:51:24 +0800 Subject: [PATCH 1/2] block symlink escapes --- electron/main/fileReader.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/electron/main/fileReader.ts b/electron/main/fileReader.ts index fd99dc2f7..64ce552a3 100644 --- a/electron/main/fileReader.ts +++ b/electron/main/fileReader.ts @@ -537,8 +537,9 @@ export class FileReader { 'terminal_logs' ]; - private getFilesRecursive(dirPath: string, basePath: string): FileInfo[] { + private getFilesRecursive(dirPath: string, basePath: string, baseReal?: string): FileInfo[] { try { + const resolvedBase = baseReal ?? fs.realpathSync(basePath); const files = fs.readdirSync(dirPath); const result: FileInfo[] = []; @@ -548,7 +549,13 @@ export class FileReader { if (this.hiddenFolders.includes(file)) continue; const filePath = path.join(dirPath, file); - const stats = fs.statSync(filePath); + const stats = fs.lstatSync(filePath); + if (stats.isSymbolicLink()) continue; + const realPath = fs.realpathSync(filePath); + const relativeToBase = path.relative(resolvedBase, realPath); + if (relativeToBase.startsWith('..') || path.isAbsolute(relativeToBase)) { + continue; + } const isFolder = stats.isDirectory(); const relativePath = path.relative(basePath, dirPath); @@ -563,7 +570,7 @@ export class FileReader { result.push(fileInfo); if (isFolder) { - const subFiles = this.getFilesRecursive(filePath, basePath); + const subFiles = this.getFilesRecursive(filePath, basePath, resolvedBase); result.push(...subFiles); } } @@ -906,4 +913,3 @@ export class FileReader { } } } - From 9f3bf5149cf02566ce65293bcb2f114c20820bae Mon Sep 17 00:00:00 2001 From: Wendong-Fan Date: Sun, 1 Feb 2026 23:54:39 +0800 Subject: [PATCH 2/2] minor enhance --- electron/main/fileReader.ts | 49 ++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/electron/main/fileReader.ts b/electron/main/fileReader.ts index 64ce552a3..a7c3d91ae 100644 --- a/electron/main/fileReader.ts +++ b/electron/main/fileReader.ts @@ -549,30 +549,35 @@ export class FileReader { if (this.hiddenFolders.includes(file)) continue; const filePath = path.join(dirPath, file); - const stats = fs.lstatSync(filePath); - if (stats.isSymbolicLink()) continue; - const realPath = fs.realpathSync(filePath); - const relativeToBase = path.relative(resolvedBase, realPath); - if (relativeToBase.startsWith('..') || path.isAbsolute(relativeToBase)) { + try { + const stats = fs.lstatSync(filePath); + if (stats.isSymbolicLink()) continue; + const realPath = fs.realpathSync(filePath); + const relativeToBase = path.relative(resolvedBase, realPath); + if (relativeToBase.startsWith('..') || path.isAbsolute(relativeToBase)) { + continue; + } + const isFolder = stats.isDirectory(); + const relativePath = path.relative(basePath, dirPath); + + const fileInfo: FileInfo = { + path: filePath, + name: file, + type: isFolder ? 'folder' : (file.split('.').pop()?.toLowerCase() || ''), + isFolder: isFolder, + relativePath: relativePath === '' ? '' : relativePath + }; + + result.push(fileInfo); + + if (isFolder) { + const subFiles = this.getFilesRecursive(filePath, basePath, resolvedBase); + result.push(...subFiles); + } + } catch (fileErr) { + console.warn("Skipping inaccessible file:", filePath, fileErr); continue; } - const isFolder = stats.isDirectory(); - const relativePath = path.relative(basePath, dirPath); - - const fileInfo: FileInfo = { - path: filePath, - name: file, - type: isFolder ? 'folder' : (file.split('.').pop()?.toLowerCase() || ''), - isFolder: isFolder, - relativePath: relativePath === '' ? '' : relativePath - }; - - result.push(fileInfo); - - if (isFolder) { - const subFiles = this.getFilesRecursive(filePath, basePath, resolvedBase); - result.push(...subFiles); - } } return result;