NousResearch/hermes-agent · error · Error
Unsafe SSH key path: must not start with a dash ("${keyPath}
Error message
Unsafe SSH key path: must not start with a dash ("${keyPath}"). What it means
Thrown by validateKeyPath() when the SSH key path starts with a dash. Since the path is passed as an -i argument to ssh, a leading dash would let it be parsed as an option flag, so it is rejected as an argument-injection hazard.
Source
Thrown at apps/desktop/electron/ssh-connection.ts:85
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) {
if (!keyPath) {
return
}
if (_CONTROL_CHAR_RE.test(keyPath)) {
throw new Error('Unsafe SSH key path: contains control characters.')
}
if (keyPath.startsWith('-')) {
throw new Error(`Unsafe SSH key path: must not start with a dash ("${keyPath}").`)
}
}
// Token / secret redaction
const _REDACTIONS: Array<[RegExp, string]> = [
[/(HERMES_DASHBOARD_SESSION_TOKEN=)(\S+)/g, '$1<redacted>'],
[/(X-Hermes-Session-Token["']?\s*[:=]\s*["']?)([^\s"'&]+)/gi, '$1<redacted>'],
[/(Authorization["']?\s*:\s*Bearer\s+)(\S+)/gi, '$1<redacted>'],
[/([?&](?:token|ticket)=)([^\s&"']+)/gi, '$1<redacted>']
]
function redactSecrets(text) {
let out = String(text == null ? '' : text)
for (const [re, repl] of _REDACTIONS) {
out = out.replace(re, repl)
}View on GitHub (pinned to c896c09c42)
Solutions
- Use a proper absolute path to the key file, e.g. /home/user/.ssh/id_ed25519.
- Fix the upstream bug that produced a leading-dash path string.
- Validate at config save: reject keyPath.startsWith('-').
Example fix
// before
new SshConnection({ host, keyPath: '-i /home/me/.ssh/id' })
// after
new SshConnection({ host, keyPath: '/home/me/.ssh/id_ed25519' }) Defensive patterns
Strategy: validation
Validate before calling
if (keyPath && typeof keyPath === 'string' && keyPath.startsWith('-')) {
rejectConfig('SSH key path must be an absolute path, not an option-like string')
} Type guard
function isDashSafeKeyPath(k: unknown): k is string {
return typeof k === 'string' && !k.startsWith('-')
} Try / catch
try {
validateKeyPath(keyPath)
} catch (e) {
if (e instanceof Error && e.message.includes('key path: must not start with a dash')) {
invalidateRemoteConfig('key path field contains an ssh-flag-like value')
return
}
throw e
} Prevention
- Use a file picker or path.normalize on user input for key paths.
- Accept only absolute paths for keyPath in the settings UI.
- Do not let users paste full ssh -i command fragments into config fields.
When it happens
Trigger: cfg.keyPath beginning with '-', e.g. '-oProxyCommand=...' or a malformed path like '-keys/id_rsa'.
Common situations: User pastes an ssh option into the key path field; a path-joining bug producing '-' + segment; crafted config input.
Related errors
- Unsafe SSH target: host must not start with a dash ("${host}
- Unsafe SSH target: user must not start with a dash ("${user}
- Unsafe SSH target: host contains control characters.
- Unsafe SSH target: user contains control characters.
- Unsafe SSH key path: contains control characters.
AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14).
Data as JSON: /api/errors/c18a71c2676ecbc5.
Report an issue: GitHub.