{"record":{"id":"0646ed89044d1755","repo":"jdx/mise","slug":"brew-cask-refusing-elevated-operation-through-mut","errorCode":null,"errorMessage":"brew-cask: refusing elevated operation through mutable directory {}","messagePattern":"brew-cask: refusing elevated operation through mutable directory (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/system/packages/brew/cask.rs","lineNumber":1884,"sourceCode":"        target\n            .file_name()\n            .ok_or_else(|| eyre!(\"brew-cask: generic artifact target has no filename\"))?,\n    ))\n}\n\n#[cfg(unix)]\nfn validate_strict_elevated_ancestors(path: &Path) -> Result<()> {\n    use std::os::unix::fs::MetadataExt;\n    let stable_prefix = file::desymlink_path(&prefix::prefix());\n    for directory in path.ancestors() {\n        let metadata = directory.symlink_metadata()?;\n        if !strict_elevated_directory_is_trusted(\n            directory,\n            &stable_prefix,\n            metadata.uid(),\n            metadata.mode(),\n        ) {\n            bail!(\n                \"brew-cask: refusing elevated operation through mutable directory {}\",\n                directory.display()\n            );\n        }\n    }\n    Ok(())\n}\n\n#[cfg(unix)]\nfn strict_elevated_directory_is_trusted(\n    directory: &Path,\n    stable_prefix: &Path,\n    uid: u32,\n    mode: u32,\n) -> bool {\n    uid == 0\n        && mode & 0o002 == 0\n        // Intel Homebrew conventionally uses root:admin 0775 for /usr/local.","sourceCodeStart":1866,"sourceCodeEnd":1902,"githubUrl":"https://github.com/jdx/mise/blob/9dcfcaa0dc8747a2577d3270b69bb9d8313b2807/src/system/packages/brew/cask.rs#L1866-L1902","documentation":"Before performing elevated (privileged) file operations, mise walks every ancestor of the target path and requires each directory to be trusted: owned by root, not world-writable, and group-writable only when it is exactly the Homebrew prefix (the Intel /usr/local root:admin 0775 convention). If any ancestor is user-owned or more permissive, the elevated operation is refused — writing through a mutable directory with privileges would let anyone on the machine plant or swap the file being installed.","triggerScenarios":"A cask artifact whose target lives under a user-writable directory (e.g. /Users/<you>/bin, /tmp/...) while mise escalates to install it, or a target under /usr/local where a non-prefix subdirectory is group-writable.","commonSituations":"Niche casks with artifact targets inside $HOME; systems where directories under /usr/local were chmod'ed to 0775+ by admin tooling; mixed Homebrew prefix conventions on Intel Macs.","solutions":["Fix ownership/permissions of the offending directory (named in the error): sudo chown root:admin <dir> && sudo chmod 755 <dir>","Group-writability is only tolerated on the Homebrew prefix itself; tighten subdirectories","Avoid casks whose artifact targets live in user-writable paths — report them to the tap"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"use std::os::unix::fs::MetadataExt;\nfn elevated_path_trusted(path: &Path, prefix: &Path) -> Result<bool> {\n    for dir in path.ancestors() {\n        let m = dir.symlink_metadata()?;\n        let group_ok = m.mode() & 0o020 == 0 || dir == prefix;\n        if !(m.uid() == 0 && m.mode() & 0o002 == 0 && group_ok) {\n            return Ok(false);\n        }\n    }\n    Ok(true)\n}\n// call before requesting any elevated cask install","typeGuard":null,"tryCatchPattern":"Catch 'refusing elevated operation through mutable directory' and fix the named directory's ownership/permissions; never catch-and-continue with a different, less-checked path.","preventionTips":["Keep artifact target directories root-owned and 755 (group-writable only on the Homebrew prefix itself)","Avoid casks that install into user-writable paths with elevation","Audit /usr/local subdirectories for stray admin-writable modes on Intel Macs"],"tags":["homebrew","cask","sudo","permissions","security","mise"],"backgroundTag":"insecure-file-permissions","analyzedSha":"9dcfcaa0dc8747a2577d3270b69bb9d8313b2807","analyzedAt":"2026-08-17T14:28:50.624Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}