@@ -253,28 +253,50 @@ class Unpack extends parse_js_1.Parser {
253253 // return false if we need to skip this file
254254 // return true if the field was successfully sanitized
255255 [ STRIPABSOLUTEPATH ] ( entry , field ) {
256- const path = entry [ field ] ;
257- if ( ! path || this . preservePaths )
256+ const p = entry [ field ] ;
257+ const { type } = entry ;
258+ if ( ! p || this . preservePaths )
258259 return true ;
259- const parts = path . split ( '/' ) ;
260+ const parts = p . split ( '/' ) ;
260261 if ( parts . includes ( '..' ) ||
261262 /* c8 ignore next */
262263 ( isWindows && / ^ [ a - z ] : \. \. $ / i. test ( parts [ 0 ] ?? '' ) ) ) {
263- this . warn ( 'TAR_ENTRY_ERROR' , `${ field } contains '..'` , {
264- entry,
265- [ field ] : path ,
266- } ) ;
267- // not ok!
268- return false ;
264+ // For linkpath, check if the resolved path escapes cwd rather than
265+ // just rejecting any path with '..' - relative symlinks like
266+ // '../sibling/file' are valid if they resolve within the cwd.
267+ // For paths, they just simply may not ever use .. at all.
268+ if ( field === 'path' || type === 'Link' ) {
269+ this . warn ( 'TAR_ENTRY_ERROR' , `${ field } contains '..'` , {
270+ entry,
271+ [ field ] : p ,
272+ } ) ;
273+ // not ok!
274+ return false ;
275+ }
276+ else {
277+ // Resolve linkpath relative to the entry's directory.
278+ // `path.posix` is safe to use because we're operating on
279+ // tar paths, not a filesystem.
280+ const entryDir = node_path_1 . default . posix . dirname ( entry . path ) ;
281+ const resolved = node_path_1 . default . posix . normalize ( node_path_1 . default . posix . join ( entryDir , p ) ) ;
282+ // If the resolved path escapes (starts with ..), reject it
283+ if ( resolved . startsWith ( '../' ) || resolved === '..' ) {
284+ this . warn ( 'TAR_ENTRY_ERROR' , `${ field } escapes extraction directory` , {
285+ entry,
286+ [ field ] : p ,
287+ } ) ;
288+ return false ;
289+ }
290+ }
269291 }
270292 // strip off the root
271- const [ root , stripped ] = ( 0 , strip_absolute_path_js_1 . stripAbsolutePath ) ( path ) ;
293+ const [ root , stripped ] = ( 0 , strip_absolute_path_js_1 . stripAbsolutePath ) ( p ) ;
272294 if ( root ) {
273295 // ok, but triggers warning about stripping root
274296 entry [ field ] = String ( stripped ) ;
275297 this . warn ( 'TAR_ENTRY_INFO' , `stripping ${ root } from absolute ${ field } ` , {
276298 entry,
277- [ field ] : path ,
299+ [ field ] : p ,
278300 } ) ;
279301 }
280302 return true ;
0 commit comments