@@ -84,6 +84,11 @@ func Unzip(srcZip, destDir string, p Policy) (err error) {
8484 return err
8585 }
8686
87+ destReal := destAbs
88+ if dr , err := filepath .EvalSymlinks (destAbs ); err == nil && dr != "" {
89+ destReal = dr
90+ }
91+
8792 if p .MaxFiles > 0 && len (r .File ) > p .MaxFiles {
8893 return fmt .Errorf ("zip too many files: %d" , len (r .File ))
8994 }
@@ -129,8 +134,8 @@ func Unzip(srcZip, destDir string, p Policy) (err error) {
129134 if err != nil {
130135 return err
131136 }
132- // must be within destAbs
133- if targetAbs != destAbs && ! strings .HasPrefix (targetAbs , destAbs + string (filepath .Separator )) {
137+ // must be within destReal
138+ if targetAbs != destReal && ! strings .HasPrefix (targetAbs , destReal + string (filepath .Separator )) {
134139 return fmt .Errorf ("unsafe path escape: %q" , f .Name )
135140 }
136141
@@ -153,7 +158,7 @@ func Unzip(srcZip, destDir string, p Policy) (err error) {
153158 }
154159
155160 // Parents must not contain symlinks that leave dest, ALWAYS check
156- if bad , derr := pathHasSymlinkOutside (destAbs , targetAbs ); derr == nil && bad {
161+ if bad , derr := pathHasSymlinkOutside (destReal , targetAbs ); derr == nil && bad {
157162 return fmt .Errorf ("unsafe symlink in parents for: %q" , f .Name )
158163 } else if derr != nil && ! os .IsNotExist (derr ) { // not-exist is fine mid-extract
159164 return derr
@@ -203,22 +208,19 @@ func Unzip(srcZip, destDir string, p Policy) (err error) {
203208 parentResolved = filepath .Dir (targetAbs )
204209 }
205210 linkAbs := filepath .Join (parentResolved , filepath .Base (targetAbs ))
206- if ! isPathWithinBase (destAbs , linkAbs ) {
211+ if ! isPathWithinBase (destReal , linkAbs ) {
207212 return fmt .Errorf ("symlink destination escapes extraction root: %q" , linkAbs )
208213 }
209214 // 2. Where would the symlink, if created, point to? (Relative to resolved parent.)
210215 targetCandidate := filepath .Join (parentResolved , linkTarget )
211- // We can't EvalSymlinks on the new symlink yet, but check that the _synthetic resolution_ is within destAbs .
212- if ! isPathWithinBase (destAbs , targetCandidate ) {
216+ // We can't EvalSymlinks on the new symlink yet, but check that the _synthetic resolution_ is within destReal .
217+ if ! isPathWithinBase (destReal , targetCandidate ) {
213218 return fmt .Errorf ("symlink target escapes extraction root: %q -> %q" , f .Name , linkTarget )
214219 }
215220
216221 if err := os .Symlink (linkTarget , targetAbs ); err != nil {
217222 return fmt .Errorf ("create symlink: %w" , err )
218223 }
219- if p .PreserveTimes && ! f .Modified .IsZero () {
220- _ = os .Chtimes (targetAbs , f .Modified , f .Modified )
221- }
222224 continue
223225 }
224226
0 commit comments