fix: sanitize archive entry paths before extraction to prevent path traversal

Move path sanitization before directory handling in extractFile so
directory entries with "../" prefixes are rejected the same way file
entries already are. Add the same sanitization to extractSevenZipMultiPart
and both zip extraction loops in the Windows updater, which had no path
validation at all.
This commit is contained in:
sysy committed 2026-09-16 23:31:35 -04:00
1 parent 7c1447f659
commit 022fbf633b
3 files changed
+20 -14

No files matched your search

+10 -4
View File
@@ -37,15 +37,17 @@ func installByInstaller(killSignalChan chan<- any, packagePath, destDir string)
}
defer reader.Close()
// Find the installer file
var installerPath string
for _, file := range reader.File {
cleanName := filepath.Clean(file.Name)
if strings.HasPrefix(cleanName, "..") || filepath.IsAbs(cleanName) {
continue
}
if file.FileInfo().IsDir() {
continue
}
// Extract file
path := filepath.Join(tempDir, file.Name)
path := filepath.Join(tempDir, cleanName)
if err := os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil {
return err
@@ -101,7 +103,11 @@ func installByPortable(killSignalChan chan<- any, packagePath, destDir string) e
defer reader.Close()
for _, file := range reader.File {
path := filepath.Join(destDir, file.Name)
cleanName := filepath.Clean(file.Name)
if strings.HasPrefix(cleanName, "..") || filepath.IsAbs(cleanName) {
continue
}
path := filepath.Join(destDir, cleanName)
if file.FileInfo().IsDir() {
os.MkdirAll(path, file.Mode())
+4 -8
View File
@@ -282,19 +282,15 @@ func countArchiveFiles(archivePath string, password string) (int, error) {
// extractFile handles extracting a single file from an archive
func extractFile(ctx context.Context, fileInfo archives.FileInfo, destDir string) error {
// Skip directories, they will be created when extracting files
if fileInfo.IsDir() {
destPath := filepath.Join(destDir, fileInfo.NameInArchive)
return os.MkdirAll(destPath, fileInfo.Mode())
}
// Sanitize the path to prevent path traversal attacks
cleanPath := filepath.Clean(fileInfo.NameInArchive)
if strings.HasPrefix(cleanPath, "..") || filepath.IsAbs(cleanPath) {
// Skip files with suspicious paths
return nil
}
if fileInfo.IsDir() {
return os.MkdirAll(filepath.Join(destDir, cleanPath), fileInfo.Mode())
}
destPath := filepath.Join(destDir, cleanPath)
// Create parent directories
+6 -2
View File
@@ -4,6 +4,7 @@ import (
"io"
"os"
"path/filepath"
"strings"
"github.com/bodgit/sevenzip"
)
@@ -43,7 +44,11 @@ func extractSevenZipMultiPart(firstPartPath string, destDir string, password str
// Extract files with progress tracking
extractedFiles := 0
for _, f := range reader.File {
destPath := filepath.Join(destDir, f.Name)
cleanName := filepath.Clean(f.Name)
if strings.HasPrefix(cleanName, "..") || filepath.IsAbs(cleanName) {
continue
}
destPath := filepath.Join(destDir, cleanName)
if f.FileInfo().IsDir() {
if err := os.MkdirAll(destPath, f.Mode()); err != nil {
@@ -52,7 +57,6 @@ func extractSevenZipMultiPart(firstPartPath string, destDir string, password str
continue
}
// Ensure parent directory exists
if err := os.MkdirAll(filepath.Dir(destPath), 0755); err != nil {
return err
}