N16 name-dotdotA name with .., which climbs out of the directory the archive is extracted to.
Reject(draft) A strict parser must reject this archive.
N16-name-dotdot.tar |
test archive, 2,048 bytes
sha256 b2e00a616ca5350ef2ffa84fd48c021f035ca8483b171b37658ac7ffb8ab3a63 |
N16-name-dotdot.json | expected result |
N16-name-dotdot.txt | annotated blocks |
N16-name-dotdot.py | generator script |
The name tar-minefield/../../tar-minefield-escaped resolves to a path outside the destination. The case is rejected because the name, taken as it is, leads out of the destination, not because it is ambiguous. The file is harmless: its name and contents say what happened.
Decision point: whether a name with .. is rejected, rewritten, skipped, or followed.
Seen in: 4 PyPI sdists, such as spdk 26.9 (spdk-26.9/../scripts/rpc.py) and bt-test-interfaces 0.0.5, whose bt-test-interfaces-0.0.5/../.git/config lands next to the top directory.
Every block of 512 bytes, to scale, with its offset. Hover over a field for its bytes.
N16-name-dotdot: must reject
A name with `..`, which climbs out of the directory the archive is extracted to.
The name `tar-minefield/../../tar-minefield-escaped` resolves to a path outside the destination. The
case is rejected because the name, taken as it is, leads out of the destination, not because it is
ambiguous. The file is harmless: its name and contents say what happened.
Decision point: whether a name with `..` is rejected, rewritten, skipped, or followed.
Seen in: 4 PyPI sdists, such as spdk 26.9 (`spdk-26.9/../scripts/rpc.py`) and bt-test-interfaces
0.0.5, whose `bt-test-interfaces-0.0.5/../.git/config` lands next to the top directory.
0x000000 header: regular file
name [ 0,100) "tar-minefield/../../tar-minefield-escaped" + 59 NUL
mode [100,108) "0000644" + NUL 644 (octal)
uid [108,116) "0000000" + NUL 0
gid [116,124) "0000000" + NUL 0
size [124,136) "00000000125" + NUL 85
mtime [136,148) "00000000000" + NUL 0
chksum [148,156) "016416\0 " 7438: the unsigned sum of the header, this field as spaces
typeflag [156,157) "0" regular file
linkname [157,257) 100 NUL
magic [257,263) "ustar" + NUL
version [263,265) "00"
uname [265,297) 32 NUL
gname [297,329) 32 NUL
devmajor [329,337) "0000000" + NUL 0
devminor [337,345) "0000000" + NUL 0
prefix [345,500) 155 NUL
pad [500,512) 12 NUL
0x000200 data
85 bytes, then 427 NUL to the end of the block
"If this file is outside the directory you extracted to, the extractor followed `..`.\n"
0x000400 2 zero blocks: the end-of-archive marker
0x000800 end of file
As xxd writes it: xxd -r makes the archive of it.
00000000: 7461 722d 6d69 6e65 6669 656c 642f 2e2e tar-minefield/.. 00000010: 2f2e 2e2f 7461 722d 6d69 6e65 6669 656c /../tar-minefiel 00000020: 642d 6573 6361 7065 6400 0000 0000 0000 d-escaped....... 00000030: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000040: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000050: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000060: 0000 0000 3030 3030 3634 3400 3030 3030 ....0000644.0000 00000070: 3030 3000 3030 3030 3030 3000 3030 3030 000.0000000.0000 00000080: 3030 3030 3132 3500 3030 3030 3030 3030 0000125.00000000 00000090: 3030 3000 3031 3634 3136 0020 3000 0000 000.016416. 0... 000000a0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000000b0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000000c0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000000d0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000000e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000000f0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000100: 0075 7374 6172 0030 3000 0000 0000 0000 .ustar.00....... 00000110: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000120: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000130: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000140: 0000 0000 0000 0000 0030 3030 3030 3030 .........0000000 00000150: 0030 3030 3030 3030 0000 0000 0000 0000 .0000000........ 00000160: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000170: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000180: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000190: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000001a0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000001b0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000001c0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000001d0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000001e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000001f0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000200: 4966 2074 6869 7320 6669 6c65 2069 7320 If this file is 00000210: 6f75 7473 6964 6520 7468 6520 6469 7265 outside the dire 00000220: 6374 6f72 7920 796f 7520 6578 7472 6163 ctory you extrac 00000230: 7465 6420 746f 2c20 7468 6520 6578 7472 ted to, the extr 00000240: 6163 746f 7220 666f 6c6c 6f77 6564 2060 actor followed ` 00000250: 2e2e 602e 0a00 0000 0000 0000 0000 0000 ..`............. 00000260: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000270: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000280: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000290: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000002a0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000002b0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000002c0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000002d0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000002e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000002f0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000300: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000310: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000320: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000330: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000340: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000350: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000360: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000370: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000380: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000390: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000003a0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000003b0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000003c0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000003d0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000003e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000003f0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000400: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000410: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000420: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000430: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000440: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000450: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000460: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000470: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000480: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000490: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000004a0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000004b0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000004c0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000004d0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000004e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000004f0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000500: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000510: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000520: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000530: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000540: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000550: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000560: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000570: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000580: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000590: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000005a0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000005b0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000005c0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000005d0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000005e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000005f0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000600: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000610: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000620: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000630: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000640: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000650: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000660: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000670: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000680: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000690: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000006a0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000006b0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000006c0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000006d0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000006e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000006f0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000700: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000710: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000720: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000730: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000740: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000750: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000760: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000770: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000780: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 00000790: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000007a0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000007b0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000007c0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000007d0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000007e0: 0000 0000 0000 0000 0000 0000 0000 0000 ................ 000007f0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
| implementation | version | outcome | what it makes of it |
|---|---|---|---|
| GNU tar | tar (GNU tar) 1.35 | ✅ as the verdict says | error: tar: Removing leading `tar-minefield/../../' from member names tar: tar-minefield/../../tar-minefield-escaped: Member name contains '..' tar: Exiting with failure status due to previous errors |
| bsdtar | bsdtar 3.8.10 - libarchive 3.8.10 | ✅ as the verdict says | error: tar-minefield/../../tar-minefield-escaped: Path contains '..': Unknown error -1 bsdtar: Error exit delayed from previous errors |
| BusyBox tar | BusyBox v1.38.0, defconfig | ⚠️ accepts | tree A: tar-minefield-escaped (85 B, fc503701) |
| 7-Zip | 7-Zip (z) 26.05 (x64) | ⚠️ accepts | tree B: tar-minefield/, tar-minefield/tar-minefield-escaped (85 B, fc503701) |
| Python tarfile, filter=data, as in pip | CPython 3.15.2 | ✅ as the verdict says | error: OutsideDestinationError: 'tar-minefield/../../tar-minefield-escaped' would be extracted to 'ROOT/x/y/tar-minefield-escaped', which is outside the destination |
| Python tarfile, filter=tar | CPython 3.15.2 | ✅ as the verdict says | error: OutsideDestinationError: 'tar-minefield/../../tar-minefield-escaped' would be extracted to 'ROOT/x/y/tar-minefield-escaped', which is outside the destination |
| Python tarfile, filter=fully_trusted | CPython 3.15.2 | 💥 writes outside the destination | writes outside: x/y/tar-minefield-escaped (85 B, fc503701) |
| node-tar | tar 7.5.22 | ⚠️ accepts | tree C: nothing |
| node-tar, strict | tar 7.5.22 | ✅ as the verdict says | error: Error: TAR_ENTRY_ERROR: path contains '..' |
| tar-fs | tar-fs 3.1.3, on tar-stream 3.2.2 | ⚠️ accepts | tree A: tar-minefield-escaped (85 B, fc503701) |
| Java Commons Compress | Commons Compress 1.28.0, Expander, on Java 27.0.1.0.2 | ✅ as the verdict says | error: java.io.IOException: Zip slip 'DEST' + 'tar-minefield/../../tar-minefield-escaped' -> 'ROOT/x/y/tar-minefield-escaped' |
| .NET System.Formats.Tar | System.Formats.Tar of .NET 10.0.14, ExtractToDirectory | ✅ as the verdict says | error: IOException: Extracting the Tar entry 'tar-minefield/../../tar-minefield-escaped' would have resulted in a file outside the specified destination directory: 'DEST/' |
| PHP PharData, as in Composer | PharData of PHP 8.5.12, as Composer's TarDownloader calls it | ⚠️ accepts | tree A: tar-minefield-escaped (85 B, fc503701) |
| Go containerd archive.Apply | containerd v2.4.2, archive.Apply, of go1.27.3 | ⚠️ accepts | tree A: tar-minefield-escaped (85 B, fc503701) |
| Rust tar | tar 0.4.46, unpack | ⚠️ accepts | tree C: nothing |
| Rust astral-tokio-tar | astral-tokio-tar 0.7.0, unpack | ⚠️ accepts | tree C: nothing |
| Rust tar-codec, as in uv | tar-codec 0.0.15, with the policies of uv 0.13 | ✅ as the verdict says | error: at byte 0: unsafe member path "tar-minefield/../../tar-minefield-escaped": contains a parent-directory component |
| RubyGems | RubyGems 4.0.20 of Ruby 4.0.9, extract_tar_gz | ✅ as the verdict says | error: Gem::Package::PathError: installing into parent path ROOT/x/y/tar-minefield-escaped of DEST is not allowed |
| R untar, internal | utils::untar of R 4.6.1, tar = "internal" | ✅ as the verdict says | error: path contains '..' |
| Perl Archive::Tar | Archive::Tar 3.12 of Perl v5.44.0 | ✅ as the verdict says | error: Entry 'tar-minefield/../../tar-minefield-escaped' is attempting to leave the current working directory. Not extracting under SECURE EXTRACT MODE at contrib/matrix/runners/perl/extract.pl line 14. Cou… |
| Haskell tar | tar 0.7.2.0, extract, of GHC 9.14 | ✅ as the verdict says | error: Unsafe link target in tar archive: "tar-minefield/../../tar-minefield-escaped" |
| Julia Tar.jl | Tar 1.10.0 of Julia 1.13.3 | ✅ as the verdict says | error: path contains '..' component Tar.Header("tar-minefield/../../tar-minefield-escaped", :file, 0o644, 85, "") |
| live-bootstrap untar | mescc-tools-extra a151c245e512, as live-bootstrap pins it, built with cc | 💥 writes outside the destination | writes outside: x/y/tar-minefield-escaped (85 B, fc503701) |
| live-bootstrap untar, --non-strict | mescc-tools-extra a151c245e512, as live-bootstrap pins it, built with cc | 💥 writes outside the destination | writes outside: x/y/tar-minefield-escaped (85 B, fc503701) |
Release tarballs of Spack, nixpkgs, Guix and live-bootstrap, and samples of PyPI, crates.io and RubyGems with name.dotdot. The default policy rejects all of them.
| ecosystem | tarballs | with it | share |
|---|---|---|---|
| Spack | 37,553 | 0 | none |
| nixpkgs | 18,990 | 0 | none |
| Guix | 10,168 | 0 | none |
| PyPI | 10,000 | 4 | 0.04% |
| crates.io | 5,000 | 0 | none |
| RubyGems | 5,000 | 0 | none |
| live-bootstrap | 171 | 0 | none |
| total (distinct) | 82,586 | 4 | <0.01% |
See the list of these 4 tarballs, with the sha256 of each and an example from it.