{"record":{"id":"d8581040f8f1b730","repo":"astrid-runtime/astrid","slug":"malicious-shuttle-detected-unsupported-entry-type","errorCode":null,"errorMessage":"malicious shuttle detected: unsupported entry type for '{}' (only regular files are allowed)","messagePattern":"malicious shuttle detected: unsupported entry type for '(.+?)' \\(only regular files are allowed\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/astrid-cli/src/commands/distro/shuttle.rs","lineNumber":210,"sourceCode":"        }\n\n        let et = entry.header().entry_type();\n        if et.is_symlink() || et.is_hard_link() {\n            bail!(\n                \"malicious shuttle detected: links are not allowed ('{}')\",\n                entry_path.display()\n            );\n        }\n        // Skip directory entries — parents are created as needed below.\n        if et.is_dir() {\n            continue;\n        }\n        // Everything that survives to here must be an ordinary file. Device\n        // nodes, FIFOs, sockets, and any other special entry type are\n        // rejected: a `.shuttle` only ever legitimately carries regular\n        // files, so an exotic type is either corruption or an attack.\n        if !et.is_file() {\n            bail!(\n                \"malicious shuttle detected: unsupported entry type for '{}' \\\n                 (only regular files are allowed)\",\n                entry_path.display()\n            );\n        }\n\n        // A corrupt/undecodable size field must fail closed, not be coerced\n        // to 0 — otherwise header corruption silently bypasses the cap.\n        let size = entry\n            .header()\n            .size()\n            .context(\"malicious shuttle detected: unreadable member size\")?;\n        if size > MAX_MEMBER_BYTES {\n            bail!(\n                \"shuttle member '{}' is {size} bytes, exceeding the {MAX_MEMBER_BYTES}-byte limit\",\n                entry_path.display()\n            );\n        }","sourceCodeStart":192,"sourceCodeEnd":228,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-cli/src/commands/distro/shuttle.rs#L192-L228","documentation":"After rejecting links, `unpack` requires every remaining entry to be a regular file. Device nodes, FIFOs, sockets, and other special tar entry types are rejected because a legitimate `.shuttle` only ever carries regular files — an exotic type signals corruption or an attack.","triggerScenarios":"Calling `shuttle::unpack` on an archive containing a device node, FIFO, socket, or other non-regular/non-directory entry type (`!et.is_file()`), as covered by `unpack_rejects_non_regular_entry`.","commonSituations":"An archive crafted to smuggle device nodes, or produced by tooling that preserves special files; unpacking a truncated/mangled archive that misparses headers.","solutions":["Discard the archive — it is either corrupt or malicious; re-download or re-pack from a trusted staged directory.","Re-pack using the official `pack` flow, which only emits regular-file members.","Ensure the staging directory contains no sockets/FIFOs (e.g. leftover Unix sockets from a dev server) before packing."],"exampleFix":"// before\nstaged/run/api.sock    # leftover socket in staging dir\n// after\n$ rm staged/run/api.sock && astrid distro pack ...","handlingStrategy":"validation","validationCode":"fn only_regular_files(types: &[String]) -> bool {\n    types.iter().all(|t| t == \"file\" || t == \"dir\")\n}","typeGuard":null,"tryCatchPattern":"if let Err(e) = shuttle::unpack(archive, dest) {\n    if e.to_string().contains(\"unsupported entry type\") {\n        eprintln!(\"archive has non-file entries; discard or repack: {e}\");\n    }\n}","preventionTips":["Remove sockets/FIFOs/device files from the staging directory before packing","Use the official pack tooling, which only emits regular files","Never unpack capsules from unverified producers"],"tags":["security","archive","unpack","entry-type"],"backgroundTag":"path-traversal-blocked","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}