@@ -11,6 +11,23 @@ import (
1111 "strings"
1212)
1313
14+ // isSafeSymlinkTarget checks if a symlink target will remain within the destPath after resolution.
15+ func isSafeSymlinkTarget (linkname , destPath string ) bool {
16+ // Refuse absolute targets
17+ if filepath .IsAbs (linkname ) {
18+ return false
19+ }
20+ targetPath := filepath .Join (destPath , linkname )
21+ realTarget , err := filepath .EvalSymlinks (targetPath )
22+ if err != nil {
23+ // If cannot resolve, be conservative: refuse
24+ return false
25+ }
26+ cleanDestPath := filepath .Clean (destPath )
27+ relpath , err := filepath .Rel (cleanDestPath , realTarget )
28+ return err == nil && ! strings .HasPrefix (filepath .Clean (relpath ), ".." )
29+ }
30+
1431// ExtractTarGz extracts a .tar.gz file to the specified destination directory
1532func ExtractTarGz (srcPath , destPath string ) error {
1633 // Open the source file
@@ -78,7 +95,10 @@ func ExtractTarGz(srcPath, destPath string) error {
7895 }
7996
8097 case tar .TypeSymlink :
81- // Create symbolic link
98+ // Securely create symbolic link after validating target
99+ if ! isSafeSymlinkTarget (header .Linkname , destPath ) {
100+ return fmt .Errorf ("symlink target escapes extraction directory: %s -> %s" , fullPath , header .Linkname )
101+ }
82102 if err := os .Symlink (header .Linkname , fullPath ); err != nil {
83103 return fmt .Errorf ("failed to create symlink %s: %v" , fullPath , err )
84104 }
0 commit comments