NousResearch/hermes-agent · error · Error
Unsafe remote path: contains NUL or newline.
Error message
Unsafe remote path: contains NUL or newline.
What it means
Thrown by validateRemotePath() when a remote path matches /[\x00\n\r]/ — NUL or newline characters. Paths are shell-interpolated (expandRemotePath builds '"$HOME"' + shq(...) fragments), so these characters could terminate or split the remote command; the path is treated as unsafe injection material, not merely malformed.
Source
Thrown at apps/desktop/electron/remote-lifecycle.ts:106
function spawnLogPath(ownershipId, spawnNonce) {
return `${ownershipDirectory(ownershipId)}/${validateSpawnNonce(spawnNonce)}.log`
}
// shell-single-quote a value for safe interpolation into a remote command.
function shq(value) {
return `'${String(value).replace(/'/g, `'\\''`)}'`
}
function validateRemotePath(p) {
const s = String(p || '')
if (!s) {
throw new Error('Remote path must not be empty.')
}
// eslint-disable-next-line no-control-regex -- deliberately reject NUL in remote paths
if (/[\x00\n\r]/.test(s)) {
throw new Error('Unsafe remote path: contains NUL or newline.')
}
if (s === '~' || s.startsWith('~/') || s.startsWith('/')) {
return
}
throw new Error(`Remote path must be absolute or start with ~/: "${s}"`)
}
function expandRemotePath(p) {
validateRemotePath(p)
if (p === '~') {
return '"$HOME"'
}
if (p.startsWith('~/')) {
return '"$HOME"' + shq(p.slice(1))View on GitHub (pinned to c896c09c42)
Solutions
- Strip /[\x00\n\r]/ and trim user-supplied paths before validation (note: trim alone does not remove NUL).
- Reject or sanitize at the UI/config layer and warn the user when the input contains invisible characters.
- If the stored value legitimately contains newlines it is not a path — fix the upstream producer that corrupted it.
Example fix
// before
const expanded = expandRemotePath(rawInput)
// after
const cleaned = rawInput.replace(/[\x00\n\r]/g, '').trim()
if (!cleaned) throw new TypeError('path input was empty after sanitizing')
const expanded = expandRemotePath(cleaned) Defensive patterns
Strategy: validation
Validate before calling
function isSafeRemotePathCandidate(s: string): boolean {
return typeof s === 'string' && !/[\x00\n\r]/.test(s)
}
const candidate = String(rawPath ?? '')
if (!isSafeRemotePathCandidate(candidate)) {
rejectInput('path contains control characters (NUL/newline)')
} Type guard
function isCleanRemotePath(p: unknown): p is string {
return typeof p === 'string' && !/[\x00\n\r]/.test(p) && p.length > 0
} Try / catch
try {
cmd += expandRemotePath(p)
} catch (e) {
if (e instanceof Error && e.message === 'Unsafe remote path: contains NUL or newline.') {
throw new UserInputError(`remote path contains forbidden characters: ${JSON.stringify(p)}`)
}
throw e
} Prevention
- Strip /[\x00\n\r]/ from all user-supplied remote paths at input time.
- Trim pasted input; treat a path that is empty after trimming as missing.
- If the value was not user-entered, treat this as a potential injection attempt and audit its source.
When it happens
Trigger: Passing a path containing NUL, \n, or \r to expandRemotePath() — a value read from a corrupted config file, a copy-pasted path with a trailing line break, or programmatic concatenation that introduced a newline.
Common situations: Copy-pasting a path from a chat/doc that includes a trailing newline; a config file with CRLF line endings leaving \r inside the stored value; binary corruption of the config; malicious input attempting command injection through the remote path field.
Related errors
- ${label} exited and ${dashboardIndexUrl(baseUrl)} is served
- Remote gateway session token is required.
- SSH host is required.
- Invalid external URL
- Remote path must not be empty.
AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14).
Data as JSON: /api/errors/290629fa19bde874.
Report an issue: GitHub.