lima-vm/lima · error
ssh option %#q contains a line break
Error message
ssh option %#q contains a line break
What it means
Format() renders Lima's SSH options either as a command line (FormatCmd) or as an ssh_config block (FormatConfig). Before writing anything it scans every option string for CR/LF, because a line break inside an option value would inject extra ssh_config directives (e.g. a malicious ProxyCommand) into the generated config. It refuses the whole operation rather than produce a config vulnerable to injection.
Source
Thrown at pkg/sshutil/format.go:70
// Formats is the list of the supported formats.
var Formats = []FormatT{FormatCmd, FormatArgs, FormatOptions, FormatConfig}
func quoteOption(o string) string {
// make sure the shell doesn't swallow quotes in option values
if strings.ContainsRune(o, '"') {
o = "'" + o + "'"
}
return o
}
// Format formats the ssh options.
func Format(w io.Writer, sshPath, instName string, format FormatT, opts []string) error {
fakeHostname := hostname.FromInstName(instName) // TODO: support customization
for _, o := range opts {
// A line break in an option value (e.g. a crafted user.name) would inject
// extra ssh_config directives such as ProxyCommand into the generated config.
if strings.ContainsAny(o, "\r\n") {
return fmt.Errorf("ssh option %#q contains a line break", o)
}
}
switch format {
case FormatCmd:
args := []string{sshPath}
for _, o := range opts {
args = append(args, "-o", quoteOption(o))
}
args = append(args, fakeHostname)
// the args are similar to `limactl shell` but not exactly same. (e.g., lacks -t)
fmt.Fprintln(w, strings.Join(args, " ")) // no need to use shellescape.QuoteCommand
case FormatArgs:
var args []string
for _, o := range opts {
args = append(args, "-o", quoteOption(o))
}
fmt.Fprintln(w, strings.Join(args, " ")) // no need to use shellescape.QuoteCommand
case FormatOptions:View on GitHub (pinned to dd909d0973)
Solutions
- Find which option contains the line break (it is echoed in the error) and strip or reject it before calling Format: strings.ReplaceAll(o, "\n", " ").
- Validate upstream inputs (user.name, identities, extra ssh options in the instance config) for control characters at load time.
- If the value legitimately needs a newline, encode it differently (e.g. base64 or a config file reference) instead of passing it as an ssh option.
Example fix
// before
opts := []string{"IdentityFile=" + identity}
sshutil.Format(w, sshPath, instName, sshutil.FormatConfig, opts)
// after
identity = strings.ReplaceAll(identity, "\r", "")
identity = strings.ReplaceAll(identity, "\n", " ")
sshutil.Format(w, sshPath, instName, sshutil.FormatConfig, opts) Defensive patterns
Strategy: validation
Validate before calling
func hasLineBreak(opts []string) bool {
for _, o := range opts {
if strings.ContainsAny(o, "\r\n") {
return true
}
}
return false
}
if hasLineBreak(opts) { /* sanitize or reject before Format */ } Type guard
func safeOption(o string) bool { return !strings.ContainsAny(o, "\r\n") } Try / catch
if err := sshutil.Format(w, sshPath, instName, format, opts); err != nil {
if strings.Contains(err.Error(), "contains a line break") {
// sanitize opts and retry
}
} Prevention
- Sanitize all user-controlled values before adding them to ssh opts
- Reject control characters at config-load time
- Never pass raw multi-line strings as ssh options
When it happens
Trigger: Calling sshutil.Format (directly or via showSSHAction / writeSSHConfigFile) with an opts slice where any element contains '\n' or '\r', e.g. a crafted user.name or other value sourced from user input or the instance YAML.
Common situations: User-supplied values with embedded newlines pulled from lima.yaml, environment data, or cloud-init fields being passed into SSH option generation; attempted config-injection payloads.
Related errors
- failed to create the synced workdir in guest instance: %w
- failed to rsync to the guest %w
- failed to sync back the changes from guest instance to host:
- failed to sync back the changes from guest instance to host
- no SSH key was found, run `ssh-keygen`
AI-assisted analysis of lima-vm/lima@dd909d0973 (2026-09-01).
Data as JSON: /api/errors/7cd9a81f120c2c53.
Report an issue: GitHub.