rust-lang/cargo · critical · anyhow::Error
invalid tarball downloaded, contains an entry at {entry_path
Error message
invalid tarball downloaded, contains an entry at {entry_path:?} with invalid type {t:?} What it means
Companion guard to 177 (src/sources/registry/mod.rs:995): after the prefix check, Cargo inspects each tarball entry's `EntryType` and only allows `Regular` files and `Directory` entries. Anything else — symlinks, hardlinks, character/block devices, FIFOs — is rejected with `{t:?}` showing the offending type. This prevents tarballs from planting symlinks that could escape the unpack directory or target other files (a known supply-chain vector).
Source
Thrown at src/sources/registry/mod.rs:997
continue;
}
} else {
// We're going to unpack this tarball into the global source
// directory, but we want to make sure that it doesn't accidentally
// (or maliciously) overwrite source code from other crates. Cargo
// itself should never generate a tarball that hits this error, and
// crates.io should also block uploads with these sorts of tarballs,
// but be extra sure by adding a check here as well.
anyhow::bail!(
"invalid tarball downloaded, contains \
a file at {entry_path:?} which isn't under {prefix:?}",
)
}
// Prevent unpacking symlinks and other unexpected entry types
match entry.header().entry_type() {
EntryType::Regular | EntryType::Directory => {}
t => anyhow::bail!(
"invalid tarball downloaded, contains an entry at {entry_path:?} with invalid type {t:?}",
),
}
// Prevent unpacking the lockfile from the crate itself.
if entry_path
.file_name()
.map_or(false, |p| p == PACKAGE_SOURCE_LOCK)
{
continue;
}
// Unpacking failed
bytes_written += entry.size();
let mut result = entry.unpack_in(parent).map_err(anyhow::Error::from);
if cfg!(windows) && restricted_names::is_windows_reserved_path(&entry_path) {
result = result.with_context(|| {
format!(
"`{}` appears to contain a reserved Windows path, \View on GitHub (pinned to 0e07a15537)
Solutions
- Clear the cached tarball (`~/.cargo/registry/cache/<reg>/<pkg>-<ver>.crate`) and refetch from a trusted source.
- Re-package the crate with standard `cargo package` (which emits only regular files + dirs).
- Inspect with `tar -tvf <file>.crate` to locate the offending entry, then fix the upstream packaging tool.
- If the registry is untrusted, treat it as a supply-chain incident and stop consuming it.
Defensive patterns
Strategy: validation
Validate before calling
// Reject any tarball entry that isn't Regular or Directory.
use tar::EntryType;
fn tarball_entries_safe<R: Read>(tar: &mut tar::Archive<R>) -> bool {
for e in tar.entries().ok().into_iter().flatten() {
let t = e.header().entry_type();
if t != EntryType::Regular && t != EntryType::Directory { return false; }
}
true
} Type guard
use tar::EntryType;
pub fn entry_type_allowed(t: EntryType) -> bool {
matches!(t, EntryType::Regular | EntryType::Directory)
} Prevention
- Package crates with `cargo package` only — never custom tarball tooling that preserves symlinks.
- Treat any symlink/hardlink/device entry in a `.crate` as a security incident.
- Consume crates only from trusted registries.
When it happens
Trigger: A `.crate` archive containing a symlink, hardlink, or device/FIFO entry. Standard `cargo package` output never produces these, so encountering one implies a non-standard packaging tool, corruption, or a deliberately malicious tarball.
Common situations: A custom packaging pipeline that preserves symlinks; an attacker crafting a tarball with a symlink to overwrite files outside the crate dir; a corrupted re-packaging that turned a regular file into a link entry.
Related errors
- invalid tarball downloaded, contains a file at {entry_path:?
- failed to verify the checksum of `{}`
- path `{}` is not a blob in the git repo
- cache expected 4 bytes for index schema version
- registry said cache valid when no cache exists
AI-assisted analysis of rust-lang/cargo@0e07a15537 (2026-08-06).
Data as JSON: /data/errors/4986b5cef2b3f028.json.
Report an issue: GitHub.