@@ -154,12 +154,9 @@ func validateCopySpecs(src, dest *fileSpec) error {
154154func validateLocalDestination (destPath string ) error {
155155 destPath = filepath .Clean (destPath )
156156
157- info , err := os .Stat (destPath )
157+ _ , err := os .Stat (destPath )
158158 if err == nil {
159- if info .IsDir () {
160- return nil
161- }
162- return nil // existing file, will overwrite
159+ return nil // existing file or directory
163160 }
164161
165162 parentDir := filepath .Dir (destPath )
@@ -293,12 +290,6 @@ func (o *CopyOptions) extractTar(reader io.Reader, destPath, srcBase string) err
293290 destInfo , statErr := os .Stat (destPath )
294291 destIsDir := statErr == nil && destInfo .IsDir ()
295292
296- // Compute absolute paths for security validation
297- destPathAbs , err := filepath .Abs (destPath )
298- if err != nil {
299- return fmt .Errorf ("invalid destination path: %v" , err )
300- }
301-
302293 var baseDir string
303294 if destIsDir {
304295 baseDir = destPath
@@ -321,7 +312,7 @@ func (o *CopyOptions) extractTar(reader io.Reader, destPath, srcBase string) err
321312 }
322313
323314 // Security: validate and compute safe target path
324- targetAbs , err := computeSafeTarget (header .Name , destPath , destPathAbs , baseAbs , srcBase , destIsDir )
315+ targetAbs , err := computeSafeTarget (header .Name , destPath , baseAbs , srcBase , destIsDir )
325316 if err != nil {
326317 return err
327318 }
@@ -359,13 +350,18 @@ func (o *CopyOptions) processTarEntry(header *tar.Header, tarReader *tar.Reader,
359350 case tar .TypeSymlink :
360351 //nolint:errcheck
361352 _ , _ = fmt .Fprintf (o .IOStreams .ErrOut , "Warning: skipping symlink %s -> %s (symlinks not supported for security)\n " , header .Name , header .Linkname )
353+ case tar .TypeLink :
354+ //nolint:errcheck
355+ _ , _ = fmt .Fprintf (o .IOStreams .ErrOut , "Warning: skipping hard link %s -> %s (hard links not supported for security)\n " , header .Name , header .Linkname )
356+ default :
357+ //nolint:errcheck
358+ _ , _ = fmt .Fprintf (o .IOStreams .ErrOut , "Warning: skipping unsupported tar entry %s (type %d)\n " , header .Name , header .Typeflag )
362359 }
363360 return nil
364361}
365362
366363// computeSafeTarget validates the tar entry name and computes a safe absolute target path.
367- func computeSafeTarget (name , destPath , destPathAbs , baseAbs , srcBase string , destIsDir bool ) (string , error ) {
368-
364+ func computeSafeTarget (name , destPath , baseAbs , srcBase string , destIsDir bool ) (string , error ) {
369365 cleanName := path .Clean (name )
370366
371367 if cleanName == ".." || strings .HasPrefix (cleanName , "../" ) || path .IsAbs (cleanName ) {
@@ -393,7 +389,7 @@ func computeSafeTarget(name, destPath, destPathAbs, baseAbs, srcBase string, des
393389 return "" , fmt .Errorf (errPathTraversal , name )
394390 }
395391
396- if strings .HasPrefix (rel , ".." ) {
392+ if rel == ".." || strings .HasPrefix (rel , ".." + string ( filepath . Separator ) ) {
397393 return "" , fmt .Errorf (errPathTraversal , name )
398394 }
399395
0 commit comments