{"record":{"id":"a6a59fc7a7b2bacc","repo":"jdx/mise","slug":"invalid-remote-kind-value","errorCode":null,"errorMessage":"invalid remote {kind}: {value}","messagePattern":"invalid remote (.+?): (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/remote.rs","lineNumber":1460,"sourceCode":"            base.join(path)\n        };\n        absolutize(&path)\n    })\n    .transpose()\n}\n\nfn absolutize(path: &Path) -> Result<PathBuf> {\n    if path.is_absolute() {\n        Ok(path.to_path_buf())\n    } else {\n        Ok(std::env::current_dir()?.join(path))\n    }\n}\n\nfn validate_ssh_atom(kind: &str, value: &str) -> Result<()> {\n    validate_value(kind, value)?;\n    if value.starts_with('-') || value.chars().any(char::is_whitespace) {\n        bail!(\"invalid remote {kind}: {value}\");\n    }\n    Ok(())\n}\n\nfn validate_value(kind: &str, value: &str) -> Result<()> {\n    if value.is_empty() || value.contains('\\0') {\n        bail!(\"remote {kind} cannot be empty or contain NUL\");\n    }\n    Ok(())\n}\n\nfn validate_staging_path(path: &str) -> Result<()> {\n    if !path.starts_with(\"/tmp/mise-bootstrap.\")\n        || path[\"/tmp/mise-bootstrap.\".len()..].is_empty()\n        || path.chars().any(char::is_whitespace)\n    {\n        bail!(\"remote mktemp returned an unsafe staging path: {path:?}\");\n    }","sourceCodeStart":1442,"sourceCodeEnd":1478,"githubUrl":"https://github.com/jdx/mise/blob/9dcfcaa0dc8747a2577d3270b69bb9d8313b2807/src/system/remote.rs#L1442-L1478","documentation":"Values that become single argv atoms in the ssh command line (host name, user, port-like scalars) are validated by validate_ssh_atom: after the non-empty/no-NUL check, a value may not start with '-' and may not contain whitespace. This prevents argument injection into the ssh command and keeps atoms atomic; this error means a configured value violates that.","triggerScenarios":"Configuration load/merge (RemoteHost::validate) or any validate_ssh_atom call site with a value like '-oProxyCommand=...' in a host/user field, or 'my user' / 'build server' containing spaces. Whitespace would split the atom into multiple ssh arguments; a leading dash would be parsed as an ssh flag.","commonSituations":"Copy-pasted ssh_config fragments into mise.toml remote host entries, usernames containing spaces (e.g. corporate 'first last' accounts), or accidentally putting ssh options into the host field.","solutions":["Put options in ssh_options (as separate single-atom strings) instead of embedding them in host/user","Remove leading dashes: the host must be a hostname/alias, user a single token","For usernames with spaces, create an SSH alias in ~/.ssh/config and reference the alias as the host","Quote values in TOML only as needed — quoting does not bypass the check, the characters themselves are rejected"],"exampleFix":"# before (mise.toml)\n[remote.hosts.bad]\nssh = \"-J bastion build.example.com\"\n\n# after\n[remote.hosts.bad]\nssh = \"build.example.com\"\nssh_options = [\"-J\", \"bastion\"]","handlingStrategy":"validation","validationCode":"# lint remote host config before applying\nfor v in \"$SSH_HOST\" \"$SSH_USER\"; do\n  case \"$v\" in -*) echo \"value starts with dash: $v\";; esac\n  case \"$v\" in *[[:space:]]*) echo \"value has whitespace: $v\";; esac\ndone","typeGuard":"fn isSshAtom(value: &str) -> bool {\n    !value.is_empty()\n        && !value.contains('\\0')\n        && !value.starts_with('-')\n        && !value.chars().any(char::is_whitespace)\n}","tryCatchPattern":"if !isSshAtom(&host_value) {\n    return Err(eyre::eyre!(\"invalid remote host value: {host_value}\"));\n}\nlet session = SshSession::new(host)?;","preventionTips":["Keep host/user fields to single tokens; move options into ssh_options","Use ~/.ssh/config aliases instead of embedding options in host strings","Validate generated mise.toml with a config linter in CI"],"tags":["remote","ssh","validation","argument-injection","config"],"backgroundTag":"ssh-argument-validation-failed","analyzedSha":"9dcfcaa0dc8747a2577d3270b69bb9d8313b2807","analyzedAt":"2026-08-17T14:28:50.624Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}