astrid-runtime/astrid · critical
malicious shuttle detected: links are not allowed ('{}')
Error message
malicious shuttle detected: links are not allowed ('{}') What it means
`unpack` rejects any archive member whose tar entry type is a symlink or hard link. Links could redirect writes to arbitrary filesystem locations, so a `.shuttle` may only carry regular files; any link entry is treated as tampering or corruption.
Source
Thrown at crates/astrid-cli/src/commands/distro/shuttle.rs:196
let entry_path = entry
.path()
.context("invalid path in shuttle")?
.into_owned();
if entry_path.is_absolute()
|| entry_path
.components()
.any(|c| matches!(c, Component::ParentDir))
{
bail!(
"malicious shuttle detected: invalid path '{}'",
entry_path.display()
);
}
let et = entry.header().entry_type();
if et.is_symlink() || et.is_hard_link() {
bail!(
"malicious shuttle detected: links are not allowed ('{}')",
entry_path.display()
);
}
// Skip directory entries — parents are created as needed below.
if et.is_dir() {
continue;
}
// Everything that survives to here must be an ordinary file. Device
// nodes, FIFOs, sockets, and any other special entry type are
// rejected: a `.shuttle` only ever legitimately carries regular
// files, so an exotic type is either corruption or an attack.
if !et.is_file() {
bail!(
"malicious shuttle detected: unsupported entry type for '{}' \
(only regular files are allowed)",
entry_path.display()
);View on GitHub (pinned to affd8760f4)
Solutions
- Re-pack using the project's `pack` command, after removing or dereferencing symlinks in the staged directory.
- Use `tar --dereference` equivalents: copy the tree with `cp -rL` so links become regular files, then pack.
- Do not install untrusted archives that contain links.
Example fix
// before $ tar cf capsule.shuttle staged/ # includes symlinks // after $ cp -rL staged/ staged-flat/ # dereference links $ astrid distro pack ... # repack with regular files
Defensive patterns
Strategy: validation
Validate before calling
// before unpacking an unknown archive, inspect entry types
// tar -tvf x.shuttle | grep -E '\->|^h' # links present?
fn archive_has_links(member_types: &[&str]) -> bool {
member_types.iter().any(|t| t.contains("->"))
} Try / catch
if let Err(e) = shuttle::unpack(archive, dest) {
if e.to_string().contains("links are not allowed") {
eprintln!("archive contains links; repack with dereferenced files: {e}");
}
} Prevention
- Stage capsules from directories without symlinks (use `cp -rL`)
- Never hand-build capsules with raw tar over build output
- Treat link-containing archives as untrusted
When it happens
Trigger: Calling `shuttle::unpack` on an archive containing a symlink (`et.is_symlink()`) or hard-link (`et.is_hard_link()`) entry, e.g. one built with the system `tar` that included links.
Common situations: Building a capsule by hand with `tar cf` from a directory that contains symlinks (common in node_modules or build output), or a maliciously crafted archive.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- capsule archive contains a link or special file {name}
- durable capsule archive contains a link or special file
- malicious shuttle detected: invalid path '{}'
- malicious shuttle detected: unsupported entry type for '{}'
- authenticated AstridFS.app is redirected or not a directory
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/98e4143dff5c99a0.
Report an issue: GitHub.