{"record":{"id":"4986b5cef2b3f028","repo":"rust-lang/cargo","slug":"invalid-tarball-downloaded-contains-an-entry-at","errorCode":null,"errorMessage":"invalid tarball downloaded, contains an entry at {entry_path:?} with invalid type {t:?}","messagePattern":"invalid tarball downloaded, contains an entry at (.+?) with invalid type (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/sources/registry/mod.rs","lineNumber":1008,"sourceCode":"                continue;\n            }\n        } else {\n            // We're going to unpack this tarball into the global source\n            // directory, but we want to make sure that it doesn't accidentally\n            // (or maliciously) overwrite source code from other crates. Cargo\n            // itself should never generate a tarball that hits this error, and\n            // crates.io should also block uploads with these sorts of tarballs,\n            // but be extra sure by adding a check here as well.\n            anyhow::bail!(\n                \"invalid tarball downloaded, contains \\\n                     a file at {entry_path:?} which isn't under {prefix:?}\",\n            )\n        }\n\n        // Prevent unpacking symlinks and other unexpected entry types\n        match entry.header().entry_type() {\n            EntryType::Regular | EntryType::Directory => {}\n            t => anyhow::bail!(\n                \"invalid tarball downloaded, contains an entry at {entry_path:?} with invalid type {t:?}\",\n            ),\n        }\n\n        // Prevent unpacking the lockfile from the crate itself.\n        if entry_path\n            .file_name()\n            .map_or(false, |p| p == PACKAGE_SOURCE_LOCK)\n        {\n            continue;\n        }\n        // Unpacking failed\n        bytes_written += entry.size();\n        let mut result = entry.unpack_in(parent).map_err(anyhow::Error::from);\n        if cfg!(windows) && restricted_names::is_windows_reserved_path(&entry_path) {\n            result = result.with_context(|| {\n                format!(\n                    \"`{}` appears to contain a reserved Windows path, \\","sourceCodeStart":990,"sourceCodeEnd":1026,"githubUrl":"https://github.com/rust-lang/cargo/blob/98a09e7e7d62850f14e5b6132101fc1edd19a16f/src/sources/registry/mod.rs#L990-L1026","documentation":"During unpacking, after the prefix check passes, Cargo only permits `Regular` and `Directory` tar entry types. Any other type (symlink, hardlink, char/block device, fifo) is rejected to prevent symlinks escaping the unpack dir or device-file attacks. The error names the offending entry path and the invalid type.","triggerScenarios":"`entry.header().entry_type()` is neither `Regular` nor `Directory`. Most commonly a `Symlink` entry, but also hardlinks, character/block devices, fifos, or contiguous-file types. Caused by a tarball containing links/devices that Cargo forbids.","commonSituations":"A crate packaged with symlinks (e.g. by a non-cargo packager or `tar` preserving symlinks from the source tree); a tampered tarball embedding device files; registry mirror re-packaging that introduced links; cross-platform packaging where symlinks were used on Linux.","solutions":["Re-package the crate with `cargo package` (which excludes symlinks), then re-publish.","Replace the offending tarball in cache: `rm ~/.cargo/registry/cache/<index>/<pkg>-<ver>.crate` and refetch from a trusted registry.","Remove symlinks from the crate's source tree before packaging.","Audit the registry for crates with non-regular entries."],"exampleFix":"# before: crate contains a symlink\n$ tar tvf mycrate-1.0.0.crate\nlrwxrwxrwx ... mycrate-1.0.0/lib/orig\n\n# after: repackage without symlinks\n$ rm crate-src/lib/orig        # or copy the target file in\n$ cargo package\n# now tar entries are Regular/Directory only","handlingStrategy":"validation","validationCode":"fn validate_tarball_entry_types(tar_path: &Path) -> Result<(), anyhow::Error> {\n    let mut a = tar::Archive::new(std::fs::File::open(tar_path)?);\n    for e in a.entries()? {\n        let e = e?;\n        match e.header().entry_type() {\n            tar::EntryType::Regular | tar::EntryType::Directory => {},\n            t => anyhow::bail!(\"disallowed entry type {:?} at {:?}\", t, e.path()?),\n        }\n    }\n    Ok(())\n}","typeGuard":"fn tarball_has_only_regular_entries(path: &std::path::Path) -> bool {\n    std::fs::File::open(path).ok()\n        .and_then(|f| tar::Archive::new(f).entries().ok())\n        .map_or(false, |mut es| es.all(|e| e.map_or(false, |e| matches!(e.header().entry_type(), tar::EntryType::Regular | tar::EntryType::Directory))))\n}","tryCatchPattern":"match entry.header().entry_type() {\n    EntryType::Regular | EntryType::Directory => {},\n    _ => {\n        // recover by re-fetching from a trusted registry\n        refetch_crate(pkg)?;\n        return unpack(...);\n    }\n}","preventionTips":["Strip symlinks from crate source trees before packaging.","Always publish with `cargo package` / `cargo publish`.","Audit registry mirrors for non-regular tar entries.","Re-fetch suspect crates from crates.io before unpacking."],"tags":["cargo","registry","tarball","unpack","security","symlink","integrity"],"backgroundTag":null,"analyzedSha":"98a09e7e7d62850f14e5b6132101fc1edd19a16f","analyzedAt":"2026-08-11T17:42:36.556Z","contentChangedAt":"2026-08-11T17:42:36.556Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}