{"record":{"id":"3969102b4aa3eff0","repo":"jdx/mise","slug":"the-packslip-names-an-executable-which-is-no","errorCode":null,"errorMessage":"the packslip names an executable {:?}, which is not a plain file name","messagePattern":"the packslip names an executable (.+?), which is not a plain file name","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/backend/packslip.rs","lineNumber":929,"sourceCode":"                \"packslip:{project}: {} of {before} version(s) carry a stamp\",\n                versions.len()\n            );\n        }\n        Ok(versions)\n    }\n\n    /// Put every executable the packslip names into the install's bin dir\n    /// under the name it should have on PATH.\n    fn link_bins(tv: &ToolVersion, artifact: &Artifact) -> Result<()> {\n        if artifact.bin.is_empty() {\n            return Ok(());\n        }\n        let install_path = tv.install_path();\n        let bins_dir = install_path.join(MISE_BINS_DIR);\n        file::create_dir_all(&bins_dir)?;\n        for bin in &artifact.bin {\n            if !file::is_plain_file_name(&bin.name) {\n                bail!(\n                    \"the packslip names an executable {:?}, which is not a plain file name\",\n                    bin.name\n                );\n            }\n            let Some(src) = locate_in_install(&install_path, &bin.path) else {\n                bail!(\n                    \"the packslip lists executable {} in {}, but the archive holds no such file\",\n                    bin.path,\n                    artifact.name\n                );\n            };\n            file::make_executable(&src)?;\n            let dst = bins_dir.join(&bin.name);\n            if dst.exists() || dst.is_symlink() {\n                file::remove_all(&dst)?;\n            }\n            file::make_symlink_or_copy(&src, &dst)?;\n        }","sourceCodeStart":911,"sourceCodeEnd":947,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/backend/packslip.rs#L911-L947","documentation":"When linking installed binaries into the bins directory, mise validates that each executable name declared in the packslip manifest is a plain file name (no path separators, no `..`, etc.). A name like `sub/dir/tool` or `../tool` is rejected because it would create links outside the bins directory. This is a path-traversal safety check on vendor-supplied manifests.","triggerScenarios":"link_bins during install of a packslip: tool when `artifact.bin[i].name` contains path components, absolute paths, or traversal segments and fails file::is_plain_file_name.","commonSituations":"A hand-written or malicious packslip manifest declares a bin name with a slash or `..`; a vendor ships a malformed manifest after renaming binaries; typo in a locally-authored packslip.","solutions":["Fix the packslip manifest so each bin `name` is a bare file name (e.g. `mytool`, not `bin/mytool` or `../mytool`)","Report the manifest to the vendor/packslip author if it's an upstream release","Verify the manifest you trusted hasn't been swapped — check the signature/digests"],"exampleFix":"// before (packslip manifest)\n[[bin]]\nname = \"subdir/mytool\"\n// after\n[[bin]]\nname = \"mytool\"","handlingStrategy":"validation","validationCode":"fn is_plain_bin_name(name: &str) -> bool {\n    !name.is_empty()\n        && !name.contains('/')\n        && !name.contains('\\\\')\n        && name != \".\"\n        && name != \"..\"\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["When authoring packslips, always use bare file names for bin entries","Review vendor manifests for path-like bin names before adopting them","Treat any bin name with separators as a red flag for tampering"],"tags":["packslip","path-traversal","validation","manifest"],"backgroundTag":"path-traversal-blocked","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}