{"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":2010,"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":1992,"sourceCodeEnd":2028,"githubUrl":"https://github.com/jdx/mise/blob/6f52dcdf99e282ef7a7db68c81301fa4618d0f79/src/system/packages/brew/cask.rs#L1992-L2028","documentation":"validate_strict_elevated_ancestors (src/system/packages/brew/cask.rs:2010) walks every ancestor of a path a sudo operation will write through and requires each to be trusted: root-owned (uid 0), not world-writable, and group-writable only for the exact Homebrew prefix itself (the Intel root:admin 0775 /usr/local exception in strict_elevated_directory_is_trusted). Any mutable directory — user-owned, group-writable, or reached via untrusted symlinks — aborts the privileged copy.","triggerScenarios":"A cask artifact target whose path traverses a user-owned or group/world-writable directory: custom targets pointing into /Users/.../bin or a chmod 0777/0775 dir, or symlinked components resolving into untrusted locations during the ancestor walk.","commonSituations":"Custom artifact target paths in cask stanzas on shared machines; directories loosened to 0775/0777 for convenience; Intel Macs where /usr/local subdirectories were chowned to the admin user; relocated brew prefixes outside the trusted prefix.","solutions":["Install to the default locations mise/Homebrew use — root-owned ancestors with no group/world write — instead of custom writable targets","Tighten the offending directory named in the error: sudo chown root <dir> && sudo chmod go-w <dir>","Replace user-owned symlinks in the ancestor chain with real directories (desymlink the path)","If the dir is Intel brew's 0775 prefix, ensure it is exactly the configured brew prefix — the exception applies only there"],"exampleFix":"# before\n$ sudo chmod -R g+w /opt/tools   # ancestors became group-writable\n$ mise install brew-cask:foo    # refuses elevated operation through /opt/tools\n\n# after\n$ sudo chown root /opt/tools && sudo chmod go-w /opt/tools\n$ mise install brew-cask:foo","handlingStrategy":"validation","validationCode":"for dir in target.ancestors() {\n    let md = dir.symlink_metadata()?;\n    let trusted = md.uid() == 0 && md.mode() & 0o002 == 0;\n    if !trusted {\n        return Err(anyhow!(\"mutable ancestor {} - refusing elevated operation\", dir.display()));\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Install cask artifacts to default root-owned locations, not custom user-writable trees","chmod go-w every directory a sudo copy traverses","Replace user-owned symlinks in target paths with real directories before installing"],"tags":["brew-cask","security","sudo","permissions","privilege-escalation"],"backgroundTag":"insecure-install-path","analyzedSha":"6f52dcdf99e282ef7a7db68c81301fa4618d0f79","analyzedAt":"2026-08-22T10:14:23.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}