jdx/mise · error

brew-cask: app target '{target_name}' must not contain '..'

Error message

brew-cask: app target '{target_name}' must not contain '..'

What it means

`app_target_path` validates a cask `app` artifact's target path before mise links it into the applications directory. Targets that contain a `/` are parsed as absolute paths, and any `..` component would let the target escape the app-dir containment boundary (symlinks here may be created with elevated privileges). mise rejects such targets with this error as a path-traversal safeguard.

Source

Thrown at src/system/packages/brew/cask/paths.rs:124

            return false;
        }
    }
    true
}

pub(super) fn app_target_path(target_name: &str) -> Result<PathBuf> {
    let app_dir = target_app_dir()?;
    if target_name.contains('\0') {
        bail!("brew-cask: app target contains NUL");
    }
    if target_name.contains('/') {
        let target = target_name.replace("$HOMEBREW_PREFIX", &prefix::prefix().to_string_lossy());
        let path = PathBuf::from(target);
        if path
            .components()
            .any(|component| matches!(component, Component::ParentDir))
        {
            bail!("brew-cask: app target '{target_name}' must not contain '..'");
        }
        if path.is_absolute() {
            let prefix_app_dir = prefix::prefix().join("Applications");
            if path.starts_with(&app_dir) || path.starts_with(&prefix_app_dir) {
                return Ok(path);
            }
            // Casks routinely hardcode an absolute `/Applications/Foo.app`
            // target. When an override appdir is configured, relocate such a
            // target into it (preserving any subdirectories) rather than
            // rejecting it. `$HOMEBREW_PREFIX`-anchored targets are handled by
            // the check above and are never relocated.
            if app_dir != Path::new(DEFAULT_APP_DIR)
                && let Ok(rest) = path.strip_prefix(DEFAULT_APP_DIR)
            {
                return Ok(app_dir.join(rest));
            }
            bail!(
                "brew-cask: app target '{target_name}' must be under {}",

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Remove any `..` components from the cask's `app target:` value and use a plain app-bundle name (e.g. `Foo.app`) or an absolute path under the app dir
  2. If the target should live elsewhere, set an absolute override directory via the brew-cask APP_DIR env var (validated separately) instead of using `..`
  3. If the cask comes from upstream, verify it is the official definition and update the cask (`mise` refresh / brew update) so the malformed stanza is replaced
  4. For custom casks, rewrite the target as an absolute path starting with `/Applications/` or `$HOMEBREW_PREFIX/`

Example fix

// before (cask stanza)
app target: ['Foo.app', '../Utilities/Bar.app']
// after
app target: ['Foo.app', '/Applications/Utilities/Bar.app']
Defensive patterns

Strategy: validation

Validate before calling

fn app_target_ok(target: &str) -> bool {
    !target.contains('\0')
        && (!target.contains('/') || {
            let p = std::path::Path::new(target.replace("$HOMEBREW_PREFIX", "").as_str());
            !p.components().any(|c| matches!(c, std::path::Component::ParentDir))
        })
}

Type guard

fn is_safe_cask_target(t: &str) -> bool {
    !t.contains('\0') && std::path::Path::new(t).components().all(|c| !matches!(c, std::path::Component::ParentDir))
}

Try / catch

match cask.install() {
    Err(e) if e.to_string().contains("must not contain '..'") => {
        eprintln!("fix the cask target: remove '..' components");
    }
    r => r?,
}

Prevention

When it happens

Trigger: Calling cask install/validation (installed_skip_reason, install_app, app_target_paths, validate_adoptable_apps, appdir_artifact_source) with a cask whose `app target:` string contains `/` and a `..` component, e.g. `['Foo.app', '../../usr/bin']` or a malicious/edited cask stanza.

Common situations: Hand-edited or third-party cask stanzas with relative escape targets; typos in custom cask definitions; attempting to point an app target outside /Applications via `..` instead of an absolute path; copied cask from an untrusted source.

Understand the failure class

Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.

Related errors


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/f85a7483778c81ce. Report an issue: GitHub.