can1357/oh-my-pi · error
Invalid SSH host "${host}": an SSH destination must not begi
Error message
Invalid SSH host "${host}": an SSH destination must not begin with "-" (argument-injection guard) What it means
buildSshTarget is the single chokepoint that renders every SSH destination string used by connections, transfers, and sshfs mounts. SSH parses a destination argument starting with "-" as an option flag, so a hostile or corrupted host value like `-oProxyCommand=...` would be executed locally as an ssh option instead of treated as a hostname. The library throws this error to guarantee no user-controlled string can be injected into the ssh argv as an option.
Source
Thrown at packages/coding-agent/src/ssh/utils.ts:12
export function sanitizeHostName(name: string): string {
const sanitized = name.replace(/[^a-zA-Z0-9._-]+/g, "_");
return sanitized.length > 0 ? sanitized : "remote";
}
export function buildSshTarget(username: string | undefined, host: string): string {
// SSH treats a destination starting with "-" as an option, so a host/user of
// `-oProxyCommand=...` becomes local command execution. Reject before this
// string reaches any `ssh` argv (this is the single render chokepoint for
// every connection, transfer, and sshfs mount).
if (host.startsWith("-")) {
throw new Error(
`Invalid SSH host "${host}": an SSH destination must not begin with "-" (argument-injection guard)`,
);
}
if (username?.startsWith("-")) {
throw new Error(
`Invalid SSH username "${username}": an SSH username must not begin with "-" (argument-injection guard)`,
);
}
return username ? `${username}@${host}` : host;
}
/**
* Single-quote a path for a POSIX remote shell, escaping embedded single quotes.
* Mirrors the private `quoteRemotePath` in `tools/ssh.ts`; shared here for the
* `ssh://` file-transfer helpers.
*/
export function quotePosixPath(value: string): string {
if (value.length === 0) return "''";View on GitHub (pinned to 9690622007)
Solutions
- Fix the host value in your ssh:// URL or configuration so it is a real hostname (no leading dash).
- If you need ssh options (ProxyJump, port, etc.), pass them through the dedicated option fields or ~/.ssh/config, not inside the host string.
- Validate/sanitize the host before it reaches buildSshTarget, e.g. strip a scheme and reject leading dashes.
Example fix
// before buildSshTarget(undefined, "-oProxyCommand=evil") // after buildSshTarget(undefined, "jump.example.com") // put ProxyCommand in ~/.ssh/config
Defensive patterns
Strategy: validation
Validate before calling
function safeSshHost(host: string): boolean { return host.length > 0 && !host.startsWith("-"); }
if (!safeSshHost(host)) throw new Error("host must not begin with '-'"); Try / catch
try { const target = buildSshTarget(user, host); } catch (err) { log.warn("ssh target rejected", { host, err }); return; } Prevention
- Never build ssh destinations from raw URL components or user config without checking for a leading dash.
- Keep ssh options in ~/.ssh/config or dedicated option fields, never inside host/username strings.
- Treat any remote URL (repo remotes, sync targets) as untrusted input before passing to ssh.
When it happens
Trigger: Calling buildSshTarget (directly or via buildRemoteCommand/target) with a host string whose first character is "-", e.g. from a malformed ssh:// URL, a config value like `-oProxyCommand=evil`, or a parsed destination where the option separator was lost.
Common situations: A mistyped ssh:// URL such as ssh://-oProxyCommand=x@host, a config file with the host field holding ssh options instead of a hostname, or an attacker-controlled remote/repository URL attempting argument injection against tooling that shells out to ssh.
Related errors
- Invalid SSH username "${username}": an SSH username must not
- SSH control directory ${dir} ${isSymlink ? "is a symlink" :
- SSH control directory ${dir} ${reason}
- SSH key permissions must be 600 or stricter: ${keyPath}
- The managed-skills root is a symlink; refusing to operate ou
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/f3ada7c5b334b8c5.
Report an issue: GitHub.