denoland/deno · critical

refusing tar entry with traversal path: {}

Error message

refusing tar entry with traversal path: {}

What it means

Thrown while extracting the downloaded LAUFEY runtime tar archive: an entry's path contains a `..` (ParentDir) or root (RootDir) component, a classic path-traversal (tar-slip) attempt. This is a deliberate hard error — the underlying `unpack_in` would silently SKIP such entries, so the code pre-checks and refuses the whole archive instead. Since the archive passed the SHA-256 check before extraction, this indicates a malicious or corrupted UPSTREAM release, not a network issue.

Source

Thrown at cli/tools/desktop.rs:2228

    let mut archive = tar::Archive::new(decoder);
    // Strip mode bits from archive entries: a tampered archive could
    // otherwise ship setuid/setgid binaries into the deno cache. Files keep
    // the umask-applied default; we re-add execute bits below for entries
    // that need them.
    archive.set_preserve_permissions(false);
    for entry in archive.entries()? {
      let mut entry = entry?;
      let entry_path = entry.path()?.into_owned();
      // Defence in depth — pre-check `..` / root before handing to
      // `unpack_in`, since we want a hard error rather than the silent
      // skip that `unpack_in` does for a rejected entry.
      if entry_path.components().any(|c| {
        matches!(
          c,
          std::path::Component::ParentDir | std::path::Component::RootDir
        )
      }) {
        bail!(
          "refusing tar entry with traversal path: {}",
          entry_path.display()
        );
      }
      // `unpack_in` (vs. `unpack(absolute_path)`) makes tar enforce its
      // symlink + hardlink target containment too: a tar with entry A as
      // symlink `foo -> ../../etc` followed by entry B writing
      // `foo/passwd` would otherwise escape `dest`.
      if !entry.unpack_in(dest)? {
        bail!(
          "refusing tar entry that would unpack outside dest: {}",
          entry_path.display()
        );
      }
      #[cfg(unix)]
      {
        use std::os::unix::fs::PermissionsExt;
        let dest_path = dest.join(&entry_path);

View on GitHub (pinned to f7822238ca)

Solutions

  1. Do NOT bypass the check or extract the archive manually — treat it as hostile until proven otherwise.
  2. Inspect the archive safely: `tar -tvf <archive>` and look for absolute paths or `..` segments in the listing.
  3. Clear the LAUFEY cache and re-download; if the mismatch reproduces, report it immediately to the deno/laufey maintainers with the archive name and URL.
Defensive patterns

Strategy: try-catch

Try / catch

# Never bypass; surface as a security failure
if deno desktop main.ts 2>&1 | tee /tmp/d.log && grep -q "refusing tar entry" /tmp/d.log; then
  echo "SECURITY: malicious/corrupt runtime archive — report upstream" >&2; exit 2
fi

Prevention

When it happens

Trigger: A crafted laufey release tarball containing entries like `../../etc/passwd` or `/etc/launcher`; a corrupted (bit-rotted) cache producing garbage paths; an upstream packaging bug that emitted absolute paths in the tar.

Common situations: Almost never in normal use — the checksum gate means you see this only if the pinned release itself contains such entries (compromised or mis-built release) or the local cache was corrupted after verification.

Related errors


AI-assisted analysis of denoland/deno@f7822238ca (2026-08-20). Data as JSON: /api/errors/9e8603fac8846115. Report an issue: GitHub.