denoland/deno · critical
refusing symlink entry in laufey archive: {}
Error message
refusing symlink entry in laufey archive: {} What it means
Thrown while extracting a LAUFEY Windows .zip when an entry is a symlink. Symlinks are refused categorically because a symlink-then-write pair inside one archive is the standard zip-slip-via-symlink escape (extract `foo -> ../../etc`, then write `foo/passwd`), and the LAUFEY Windows archives have no legitimate need for symlinks.
Source
Thrown at cli/tools/desktop.rs:2292
};
// 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;
}
if let Some(parent) = dest_path.parent() {
std::fs::create_dir_all(parent)?;
}
let mut out = std::fs::File::create(&dest_path)?;
std::io::copy(&mut entry, &mut out)?;
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
// Mask to 0o755 / 0o644 — same policy as the tar branch.View on GitHub (pinned to f7822238ca)
Solutions
- Do not extract with alternative tools that permit symlinks; keep the archive quarantined.
- Confirm the entry: `unzip -l` / `zipinfo` shows link entries and their targets.
- Clear the cache and retry once; if it reproduces, report to the deno/laufey maintainers.
Defensive patterns
Strategy: try-catch
Try / catch
# Security abort; do not extract symlinks manually if deno desktop main.ts 2>&1 | grep -q "refusing symlink entry in laufey archive"; then echo "SECURITY: symlink in runtime zip — report upstream" >&2; exit 2 fi
Prevention
- Do not hand-extract the runtime zip — the symlink refusal blocks a write-through-symlink escape.
- Keep the cache directory under your control; untrusted local users modifying it defeats the pipeline.
- Report any symlink hit with the entry name from the message.
When it happens
Trigger: A zip containing a symlink entry (unix mode bits with S_IFLNK, or Windows symlink attributes) followed by a file that writes through it; a repackaged upstream archive that accidentally included symlinks from a Unix build.
Common situations: Not reachable via normal releases (checksum-gated); indicates a crafted archive, a compromised/mis-packaged release, or local cache corruption.
Related errors
- refusing tar entry that would unpack outside dest: {}
- refusing zip entry with unsafe path: {}
- refusing zip entry with traversal path: {}
- refusing tar 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/e3c6278d594b6e8c.
Report an issue: GitHub.