NousResearch/hermes-agent · error · Error
Unsafe SSH target: host contains control characters.
Error message
Unsafe SSH target: host contains control characters.
What it means
Thrown by validateSshTarget() when the host matches _CONTROL_CHAR_RE (/[\x00-\x1f\x7f]/). Control characters in a host can corrupt terminal output, break command construction, or smuggle escapes, so they are rejected before the ssh command line is assembled.
Source
Thrown at apps/desktop/electron/ssh-connection.ts:57
const DEFAULT_CONNECT_TIMEOUT_MS = 15_000
const DEFAULT_EXEC_TIMEOUT_MS = 20_000
const DEFAULT_FORWARD_TIMEOUT_MS = 15_000
const CONTROL_PERSIST_SECONDS = 300
// eslint-disable-next-line no-control-regex -- deliberately reject control chars in ssh targets
const _CONTROL_CHAR_RE = /[\x00-\x1f\x7f]/
function validateSshTarget(host, user, port) {
if (!host || typeof host !== 'string') {
throw new Error('Unsafe SSH target: host is required.')
}
if (host.startsWith('-')) {
throw new Error(`Unsafe SSH target: host must not start with a dash ("${host}").`)
}
if (_CONTROL_CHAR_RE.test(host)) {
throw new Error('Unsafe SSH target: host contains control characters.')
}
if (user && _CONTROL_CHAR_RE.test(user)) {
throw new Error('Unsafe SSH target: user contains control characters.')
}
if (user && user.startsWith('-')) {
throw new Error(`Unsafe SSH target: user must not start with a dash ("${user}").`)
}
const p = Number(port)
if (!Number.isInteger(p) || p < 1 || p > 65535) {
throw new Error(`Unsafe SSH port: ${port} (must be 1-65535).`)
}
}
function validateKeyPath(keyPath) {View on GitHub (pinned to c896c09c42)
Solutions
- Re-type the hostname manually, or sanitize: host.replace(/[\x00-\x1f\x7f]/g, '').trim().
- Hex-inspect the stored config entry to find which control byte is present.
- Validate at input time in the UI with the same character class.
Example fix
// before
const conn = new SshConnection({ host: rawHost, ... })
// after
const host = rawHost.replace(/[\x00-\x1f\x7f]/g, '').trim()
if (!host) throw new TypeError('host empty after sanitizing control characters')
const conn = new SshConnection({ host, ... }) Defensive patterns
Strategy: validation
Validate before calling
const CONTROL = /[\x00-\x1f\x7f]/
if (typeof host !== 'string' || CONTROL.test(host)) {
rejectConfig('SSH host contains control characters')
} Type guard
function isControlFreeString(v: unknown): v is string {
return typeof v === 'string' && !/[\x00-\x1f\x7f]/.test(v)
} Try / catch
try {
validateSshTarget(host, user, port)
} catch (e) {
if (e instanceof Error && e.message === 'Unsafe SSH target: host contains control characters.') {
host = host.replace(/[\x00-\x1f\x7f]/g, '').trim()
if (!host) throw e
validateSshTarget(host, user, port) // re-validate sanitized value
} else throw e
} Prevention
- Sanitize pasted hostnames with the same character class before storing.
- Hex-inspect stored config when connections fail with no visible cause.
- Validate host, user, and keyPath with one shared control-char check at config save time.
When it happens
Trigger: Host strings containing tab, newline, bell, escape (\x1b), NUL, or DEL — from pasted text with invisible characters, corrupted config, or crafted input.
Common situations: Copy-pasting a hostname from a PDF/chat that includes an invisible control byte; config with embedded escape sequences; a terminal paste containing a trailing \r (CRLF) that survives into the stored host.
Related errors
- Unsafe SSH target: user contains control characters.
- Unsafe SSH target: host must not start with a dash ("${host}
- Unsafe SSH target: user must not start with a dash ("${user}
- Unsafe SSH key path: contains control characters.
- Unsafe SSH key path: must not start with a dash ("${keyPath}
AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14).
Data as JSON: /api/errors/b978b60e14a90fa7.
Report an issue: GitHub.