From 7971500467dcd569d37332e2786562adc8f8002e Mon Sep 17 00:00:00 2001 From: kolaente Date: Tue, 24 Feb 2026 20:07:32 +0100 Subject: [PATCH] fix(restore): sanitize config file path to prevent zip slip Use filepath.Base() on the config file name from the zip archive before passing it to os.OpenFile, ensuring the config file is always written to the current directory regardless of what path the zip entry claims to have. --- pkg/modules/dump/restore.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pkg/modules/dump/restore.go b/pkg/modules/dump/restore.go index aa246efc0..d7b73269d 100644 --- a/pkg/modules/dump/restore.go +++ b/pkg/modules/dump/restore.go @@ -379,7 +379,10 @@ func restoreConfig(configFile, dotEnvFile *zip.File) error { return fmt.Errorf("config file too large, is %d, max size is %d", configFile.UncompressedSize64, maxConfigSize) } - outFile, err := os.OpenFile(configFile.Name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, configFile.Mode()) + // Use only the base name to prevent writing outside the working directory + sanitizedName := filepath.Base(configFile.Name) + + outFile, err := os.OpenFile(sanitizedName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, configFile.Mode()) if err != nil { return fmt.Errorf("could not open config file for writing: %w", err) } @@ -398,7 +401,7 @@ func restoreConfig(configFile, dotEnvFile *zip.File) error { _ = cfgr.Close() _ = outFile.Close() - log.Infof("The config file has been restored to '%s'.", configFile.Name) + log.Infof("The config file has been restored to '%s'.", sanitizedName) log.Infof("You can now make changes to it, hit enter when you're done.") if _, err := bufio.NewReader(os.Stdin).ReadString('\n'); err != nil { return fmt.Errorf("could not read from stdin: %w", err)