{"record":{"id":"77abecf29da5c6e3","repo":"jdx/mise","slug":"brew-cask-refusing-to-stage-cask-payload-through","errorCode":null,"errorMessage":"brew-cask: refusing to stage cask payload through a path outside the caskroom: {}","messagePattern":"brew-cask: refusing to stage cask payload through a path outside the caskroom: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/packages/brew/cask/mod.rs","lineNumber":3327,"sourceCode":"        .iter()\n        .filter_map(|app| find_app(stage, &app.source))\n        .map(|source| file::desymlink_path(&source))\n        .collect();\n    for entry in std::fs::read_dir(stage)? {\n        let source = entry?.path();\n        if !path_starts_with_resolved_root(&source, stage) {\n            continue;\n        }\n        let resolved = file::desymlink_path(&source);\n        if app_sources.contains(&resolved) {\n            continue;\n        }\n        let Some(relative) = staged_relative_path(stage, &source) else {\n            continue;\n        };\n        let target = caskroom.join(&relative);\n        if !path_starts_with_resolved_root(&target, caskroom) {\n            bail!(\n                \"brew-cask: refusing to stage cask payload through a path outside the caskroom: {}\",\n                target.display()\n            );\n        }\n        if target.symlink_metadata().is_ok() {\n            continue;\n        }\n        if let Some(parent) = target.parent() {\n            file::create_dir_all(parent)?;\n        }\n        if source.is_dir() {\n            file::copy_dir_all_preserve_symlinks(&source, &target)?;\n        } else {\n            file::copy(&source, &target)?;\n        }\n    }\n    Ok(())\n}","sourceCodeStart":3309,"sourceCodeEnd":3345,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/packages/brew/cask/mod.rs#L3309-L3345","documentation":"This error is thrown by the brew-cask staging code when the computed installation target path (caskroom + staged relative path) resolves outside the caskroom root. The library refuses to write cask payloads through paths that escape the caskroom, because such a path could overwrite arbitrary files via symlinks or '..' components in the cask payload layout.","triggerScenarios":"Calling the cask staging flow for a cask whose staged payload path, once joined to the caskroom and path-starts-with-resolved-root checked, resolves to a location outside the caskroom directory — e.g. a payload relative path containing '..' or pointing at an absolute/symlinked location.","commonSituations":"A cask definition (custom or from a registry) declares artifact paths with '../' segments or absolute paths; a malicious or corrupted cask stanza tries to write outside the install prefix; a symlink inside the caskroom points elsewhere before staging.","solutions":["Inspect the cask definition's artifact/payload paths and remove any '..' segments or absolute paths so the staged path stays inside the caskroom","Verify the cask source/registry is trusted — this message is often a deliberate safety rejection of a malformed or hostile cask","Check for pre-existing symlinks in the caskroom that redirect the target path, and remove/relink them","Update the cask to a fixed version or report the broken cask stanza upstream"],"exampleFix":"// before: payload path escapes caskroom\nlet relative = Path::new(\"../../Library/staged.bin\");\n// after: keep the staged path inside the caskroom\nlet relative = Path::new(\"Casks/staged.bin\");","handlingStrategy":"validation","validationCode":"fn is_inside_caskroom(target: &Path, caskroom: &Path) -> bool {\n    let resolved = target.canonicalize().unwrap_or_else(|_| target.to_path_buf());\n    resolved.starts_with(caskroom)\n}\n// call before staging: assert!(is_inside_caskroom(&caskroom.join(&relative), &caskroom))","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep cask artifact paths relative and free of '..' segments","Only install casks from trusted sources","Audit caskroom for symlinks before staging","Validate the cask stanza's paths in CI before deploying it"],"tags":["brew","cask","path-traversal","security"],"backgroundTag":"path-traversal-blocked","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}