denoland/deno · critical
refusing tar entry that would unpack outside dest: {}
Error message
refusing tar entry that would unpack outside dest: {} What it means
Thrown while extracting the LAUFEY runtime tar when `unpack_in(dest)` returns false for an entry — meaning the tar crate itself judged that the entry (including symlink/hardlink targets, which `unpack_in` containment-checks) would land outside the destination. It is the second layer of defence after the explicit `..`/root pre-check, and like that check it produces a hard error instead of the silent skip `unpack_in` would otherwise do.
Source
Thrown at cli/tools/desktop.rs:2238
// `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);
// `symlink_metadata` so we don't follow a just-extracted symlink
// and chmod its target.
if let Ok(meta) = std::fs::symlink_metadata(&dest_path)
&& meta.file_type().is_file()
{
// Was the entry executable? If so, mask to 0o755; otherwise 0o644.
let mode = entry.header().mode().unwrap_or(0o644);
let safe = if mode & 0o111 != 0 { 0o755 } else { 0o644 };
let mut perms = meta.permissions();
perms.set_mode(safe);View on GitHub (pinned to f7822238ca)
Solutions
- Treat the archive as untrusted; do not extract it with other tools.
- Inspect with `tar -tvf` and check symlink targets (`ls -l` on extracted copy is NOT safe — read the listing instead).
- Clear the cache, retry once, and if it reproduces report the archive name/URL to the deno/laufey maintainers.
Defensive patterns
Strategy: try-catch
Try / catch
# Non-negotiable abort — do not fall back to other extractors set +e; OUT="$(deno desktop main.ts 2>&1)"; RC=$?; set -e if grep -q "refusing tar entry that would unpack outside dest" <<<"$OUT"; then echo "SECURITY: tar containment violated — quarantine cache and report" >&2; exit 2 fi exit $RC
Prevention
- Do not extract runtime archives with tar(1) as a workaround — the guard exists because silent skips hide escapes.
- Clear the cache and re-download once to rule out local corruption.
- Report reproducible hits with the exact entry path from the message.
When it happens
Trigger: A tar containing entry A as symlink `foo -> ../../elsewhere` followed by entry B writing through `foo/`; hardlink targets pointing to paths outside dest; any entry the tar crate's containment logic rejects as escaping the extraction root.
Common situations: Only with a crafted or badly damaged upstream release archive — the checksum verified beforehand, so a genuine hit means the pinned release is hostile or broken, or local cache corruption altered paths.
Related errors
- refusing tar entry with traversal path: {}
- refusing symlink entry in laufey archive: {}
- refusing zip entry with unsafe path: {}
- refusing zip entry with traversal path: {}
- ${prefix}Linter plugin must be an object
AI-assisted analysis of denoland/deno@f7822238ca (2026-08-20).
Data as JSON: /api/errors/a8767cc276bfdf8a.
Report an issue: GitHub.