{"record":{"id":"5811a7f25399922e","repo":"jdx/mise","slug":"brew-cask-invalid-kind-value","errorCode":null,"errorMessage":"brew-cask: invalid {kind} '{value}'","messagePattern":"brew-cask: invalid (.+?) '(.+?)'","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/packages/brew/cask.rs","lineNumber":903,"sourceCode":"    if cask.token != requested_token && !trusted_alias {\n        bail!(\n            \"brew-cask: requested token '{requested_token}' does not match API token '{}'\",\n            cask.token\n        );\n    }\n    Ok(())\n}\n\nfn validate_cask_path_component(kind: &str, value: &str) -> Result<()> {\n    let mut components = Path::new(value).components();\n    let valid = !value.is_empty()\n        && !value.contains('\\0')\n        && matches!(components.next(), Some(Component::Normal(_)))\n        && components.next().is_none()\n        && value != \".metadata\"\n        && !value.starts_with(\".mise-\");\n    if !valid {\n        bail!(\"brew-cask: invalid {kind} '{value}'\");\n    }\n    Ok(())\n}\n\nasync fn fetch_and_stage(cask: &Cask, pr: Option<&dyn SingleReport>) -> Result<PathBuf> {\n    if cask.url.ends_with(\".git\") {\n        return fetch_git_clone_and_stage(cask, pr).await;\n    }\n    let archive = fetch_archive(cask, pr).await?;\n    extract_archive(cask, &archive, pr)\n}\n\nasync fn fetch_git_clone_and_stage(cask: &Cask, pr: Option<&dyn SingleReport>) -> Result<PathBuf> {\n    let extract_dir = crate::dirs::CACHE\n        .join(\"system-brew\")\n        .join(\"cask-extract\")\n        .join(format!(\"{}-{}\", cask.token, cask.version));\n    file::remove_all(&extract_dir)?;","sourceCodeStart":885,"sourceCodeEnd":921,"githubUrl":"https://github.com/jdx/mise/blob/9dcfcaa0dc8747a2577d3270b69bb9d8313b2807/src/system/packages/brew/cask.rs#L885-L921","documentation":"Defense-in-depth path validation applied to the requested token, the API token from the cask JSON, and its version: the value must be a single normal path component — non-empty, no NUL bytes, no '/' or '..' components — and must not equal the reserved '.metadata' marker or start with '.mise-' (mise's bookkeeping names). Any violation aborts before the value is ever joined into a filesystem path.","triggerScenarios":"A user requests a cask name containing slashes or '..' (brew-cask:../evil), or a malicious/corrupted tap publishes cask JSON whose token or version embeds path separators or claims the reserved '.metadata' name — which could otherwise escape the Caskroom or collide with Homebrew's marker.","commonSituations":"Script-generated config with unescaped names; hand-edited third-party taps; supply-chain probing of mise's cask pipeline.","solutions":["Use plain alphanumeric/dash tokens when requesting casks (the cask's filename in its tap)","If you maintain the tap, fix token/version fields to be single path components","If you don't control the metadata, do not install that cask — the guard is protecting you"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"fn valid_cask_component(value: &str) -> bool {\n    use std::path::{Component, Path};\n    let mut c = Path::new(value).components();\n    !value.is_empty()\n        && !value.contains('\\0')\n        && matches!(c.next(), Some(Component::Normal(_)))\n        && c.next().is_none()\n        && value != \".metadata\"\n        && !value.starts_with(\".mise-\")\n}","typeGuard":"fn is_safe_cask_token(token: &str) -> bool {\n    !token.is_empty() && !token.contains('/') && !token.contains('\\0')\n        && !token.starts_with('.') && token != \".metadata\" && !token.contains(\"..\")\n}","tryCatchPattern":"Catch the 'invalid {kind}' bail and reject the offending request/tap metadata immediately; never sanitize and continue — a bad token or version means the metadata is untrustworthy.","preventionTips":["Validate user-supplied cask names before passing them to mise","Tap authors: keep token and version to single path components (letters, digits, dashes, dots)"],"tags":["homebrew","cask","path-traversal","validation","security","mise"],"backgroundTag":"path-traversal-validation","analyzedSha":"9dcfcaa0dc8747a2577d3270b69bb9d8313b2807","analyzedAt":"2026-08-17T14:28:50.624Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}