denoland/deno · critical
refusing zip entry with traversal path: {}
Error message
refusing zip entry with traversal path: {} What it means
Thrown while extracting a LAUFEY Windows .zip during a defence-in-depth re-check: even after `enclosed_name()` accepted the entry, the extractor independently verifies the returned relative path has no ParentDir (`..`) or RootDir components and bails if it does. It guards against a future regression or parser divergence in the zip crate's own checks.
Source
Thrown at cli/tools/desktop.rs:2282
// helper has the same shape as the tar `unpack` we deliberately
// avoided (no perm masking; no defence-in-depth against zip-slip
// beyond the crate's own checks). Treat the archive as untrusted.
for i in 0..archive.len() {
let mut entry = archive.by_index(i)?;
// `enclosed_name` rejects drive labels, absolute paths and `..`
// components. Anything that fails this check is a zip-slip attempt
// (or a legitimately weird archive we don't want to handle).
let Some(rel_path) = entry.enclosed_name() else {
bail!("refusing zip entry with unsafe path: {}", entry.name());
};
// Defence in depth — re-check the components ourselves.
if rel_path.components().any(|c| {
matches!(
c,
std::path::Component::ParentDir | std::path::Component::RootDir
)
}) {
bail!(
"refusing zip entry with traversal path: {}",
rel_path.display()
);
}
// Refuse symlinks: with prior entries already extracted, a
// symlink-then-write pair is the standard zip-slip-via-symlink
// escape, and LAUFEY Windows archives have no legitimate need for
// them.
if entry.is_symlink() {
bail!(
"refusing symlink entry in laufey archive: {}",
rel_path.display()
);
}
let dest_path = dest.join(&rel_path);
if entry.is_dir() {
std::fs::create_dir_all(&dest_path)?;
continue;View on GitHub (pinned to f7822238ca)
Solutions
- Treat the archive as malicious; do not attempt extraction with other tools.
- Verify via `unzip -l` and report the exact entry path, archive name, and URL to the deno/laufey maintainers.
- Clear the cache and retry once to rule out local corruption.
Defensive patterns
Strategy: try-catch
Try / catch
# Security abort in wrappers if deno desktop main.ts 2>&1 | grep -q "refusing zip entry with traversal path"; then echo "SECURITY: traversal path in runtime zip — report upstream" >&2; exit 2 fi
Prevention
- Never weaken the double check even though the zip crate already filters.
- Reproduce once after clearing the cache to separate corruption from a hostile release.
- Include the entry path and archive URL in any upstream report.
When it happens
Trigger: Any zip entry whose normalized components still contain `..` or a leading root after enclosed_name normalization — e.g. crafted names that slip past one checker but not the other, or corrupted central-directory data producing odd paths.
Common situations: Should never fire for legitimate archives; because the checksum gate passed, a hit signals a hostile or corrupted pinned release and warrants an upstream report.
Related errors
- refusing zip entry with unsafe path: {}
- refusing tar entry with traversal path: {}
- refusing symlink entry in laufey archive: {}
- refusing tar entry that would unpack outside dest: {}
- ${prefix}Linter plugin must be an object
AI-assisted analysis of denoland/deno@f7822238ca (2026-08-20).
Data as JSON: /api/errors/166d19a4f397fcf0.
Report an issue: GitHub.