{"record":{"id":"f85a7483778c81ce","repo":"jdx/mise","slug":"brew-cask-app-target-target-name-must-not-con-f85a74","errorCode":null,"errorMessage":"brew-cask: app target '{target_name}' must not contain '..'","messagePattern":"brew-cask: app target '(.+?)' must not contain '\\.\\.'","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/packages/brew/cask/paths.rs","lineNumber":124,"sourceCode":"            return false;\n        }\n    }\n    true\n}\n\npub(super) fn app_target_path(target_name: &str) -> Result<PathBuf> {\n    let app_dir = target_app_dir()?;\n    if target_name.contains('\\0') {\n        bail!(\"brew-cask: app target contains NUL\");\n    }\n    if target_name.contains('/') {\n        let target = target_name.replace(\"$HOMEBREW_PREFIX\", &prefix::prefix().to_string_lossy());\n        let path = PathBuf::from(target);\n        if path\n            .components()\n            .any(|component| matches!(component, Component::ParentDir))\n        {\n            bail!(\"brew-cask: app target '{target_name}' must not contain '..'\");\n        }\n        if path.is_absolute() {\n            let prefix_app_dir = prefix::prefix().join(\"Applications\");\n            if path.starts_with(&app_dir) || path.starts_with(&prefix_app_dir) {\n                return Ok(path);\n            }\n            // Casks routinely hardcode an absolute `/Applications/Foo.app`\n            // target. When an override appdir is configured, relocate such a\n            // target into it (preserving any subdirectories) rather than\n            // rejecting it. `$HOMEBREW_PREFIX`-anchored targets are handled by\n            // the check above and are never relocated.\n            if app_dir != Path::new(DEFAULT_APP_DIR)\n                && let Ok(rest) = path.strip_prefix(DEFAULT_APP_DIR)\n            {\n                return Ok(app_dir.join(rest));\n            }\n            bail!(\n                \"brew-cask: app target '{target_name}' must be under {}\",","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/packages/brew/cask/paths.rs#L106-L142","documentation":"`app_target_path` rejects app targets whose path contains a `..` component (Component::ParentDir). Parent-directory traversal could escape the intended Applications directories, so any target containing `..` is refused as a path-traversal guard.","triggerScenarios":"Any app target string that yields a `..` component after `$HOMEBREW_PREFIX` expansion — e.g. `../Apps/Foo.app`, `$HOMEBREW_PREFIX/../../Foo.app` — passed through the app install/adopt/validate call sites.","commonSituations":"A typo or misused variable in a custom app target; a crafted cask definition attempting traversal; copy-pasted paths with stray `..` segments.","solutions":["Rewrite the app target as a direct absolute path under `$HOMEBREW_PREFIX/Applications` (or `/Applications`), removing all `..` segments.","Use `$HOMEBREW_PREFIX` expansion instead of relative climbing to reach the desired location.","If the target intentionally lives outside allowed roots, move the app into the prefix Applications dir and target it there."],"exampleFix":"# before\napp target: \"$HOMEBREW_PREFIX/../../Apps/MyApp.app\"\n\n# after\napp target: \"$HOMEBREW_PREFIX/Applications/MyApp.app\"","handlingStrategy":"validation","validationCode":"let p = std::path::PathBuf::from(target_name.replace(\"$HOMEBREW_PREFIX\", prefix));\nif p.components().any(|c| matches!(c, std::path::Component::ParentDir)) {\n    return Err(\"app target must not contain '..'\".into());\n}","typeGuard":"fn has_parent_dir(p: &std::path::Path) -> bool {\n    p.components().any(|c| matches!(c, std::path::Component::ParentDir))\n}","tryCatchPattern":null,"preventionTips":["Write app targets as fully-resolved paths with no '..' segments.","Use $HOMEBREW_PREFIX expansion to reach prefix locations instead of relative climbing.","Lint cask definitions for '..' in paths before installing."],"tags":["brew-cask","path-traversal","security","path-validation"],"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"}