{"record":{"id":"4a5d7b1723b1d4de","repo":"jdx/mise","slug":"brew-cask-binary-target-must-not-contain-4a5d7b","errorCode":null,"errorMessage":"brew-cask: binary target '{}' must not contain '..'","messagePattern":"brew-cask: binary target '(.+?)' must not contain '\\.\\.'","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/packages/brew/cask/paths.rs","lineNumber":298,"sourceCode":"    if target_name.contains(\"$APPDIR\") {\n        bail!(\"brew-cask: $APPDIR must prefix a binary target\");\n    }\n    let prefix = prefix::prefix();\n    let prefix_str = prefix.to_string_lossy();\n    let target_name = target_name.replace(\"$HOMEBREW_PREFIX\", prefix_str.as_ref());\n    let path = PathBuf::from(&target_name);\n    let target = if path.is_absolute() {\n        path\n    } else if target_name.contains('/') {\n        prefix.join(path)\n    } else {\n        prefix.join(\"bin\").join(path)\n    };\n    if target\n        .components()\n        .any(|component| matches!(component, Component::ParentDir))\n    {\n        bail!(\n            \"brew-cask: binary target '{}' must not contain '..'\",\n            target.display()\n        );\n    }\n    let roots = allowed_binary_target_roots();\n    if !roots.iter().any(|root| target.starts_with(root)) {\n        bail!(\n            \"brew-cask: binary target '{}' must be under {}\",\n            target.display(),\n            allowed_binary_target_roots_display(&roots)\n        );\n    }\n    Ok(target)\n}\n","sourceCodeStart":280,"sourceCodeEnd":313,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/packages/brew/cask/paths.rs#L280-L313","documentation":"After resolving a cask `binary` target (expanding `$HOMEBREW_PREFIX`, joining relative paths to the prefix/bin), `binary_target_path` rejects any resulting path containing `..` components. Like app targets, binary targets become symlinks and `..` would allow escaping the allowed roots (Homebrew prefix, `/usr/local`), so it is blocked as a traversal safeguard.","triggerScenarios":"Calling `target_path` or `binary_targets_must_stay_under_an_allowed_root` with a cask `binary` target whose resolved path includes `..` — e.g. `binary: '../escape'`, `target: '$HOMEBREW_PREFIX/bin/../../usr/tool'`, or `['tool', { target: '/opt/foo/../bin/bar' }]`.","commonSituations":"Cask stanza typos with `..`; generated targets that concatenate paths producing `..`; attempting to relocate a binary outside the prefix without an absolute path; malicious/edited third-party casks.","solutions":["Remove `..` from the target and specify the real path directly (e.g. `/usr/local/bin/tool` instead of `$HOMEBREW_PREFIX/bin/../../usr/local/bin/tool`)","Use a bare binary name to have it placed in `$HOMEBREW_PREFIX/bin` automatically","Use an absolute path under the Homebrew prefix or `/usr/local` if the binary must live outside `bin`","If the cask is upstream, refresh it — a `..` target in an official cask usually indicates a corrupted copy"],"exampleFix":"// before (cask stanza)\nbinary: [['tool', { target: '$HOMEBREW_PREFIX/bin/../../usr/local/bin/tool' }]]\n// after\nbinary: [['tool', { target: '/usr/local/bin/tool' }]]","handlingStrategy":"validation","validationCode":"fn binary_target_ok(t: &str) -> bool {\n    let resolved = t.replace(\"$HOMEBREW_PREFIX\", \"/opt/homebrew\");\n    let p = std::path::Path::new(&resolved);\n    !p.components().any(|c| matches!(c, std::path::Component::ParentDir))\n}","typeGuard":"fn no_parent_components(p: &std::path::Path) -> bool {\n    !p.components().any(|c| matches!(c, std::path::Component::ParentDir))\n}","tryCatchPattern":"match result {\n    Err(e) if e.to_string().contains(\"binary target\") && e.to_string().contains(\"must not contain '..'\") => {\n        eprintln!(\"rewrite the binary target without '..'\");\n    }\n    r => r?,\n}","preventionTips":["Never use '..' in binary targets; spell out the absolute path","Use bare names for prefix/bin placement","When building targets programmatically, join paths instead of concatenating strings","Review third-party casks for traversal patterns before installing"],"tags":["path-traversal","brew-cask","security","validation"],"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"}