{"record":{"id":"7cd9a81f120c2c53","repo":"lima-vm/lima","slug":"ssh-option-q-contains-a-line-break","errorCode":null,"errorMessage":"ssh option %#q contains a line break","messagePattern":"ssh option %#q contains a line break","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/sshutil/format.go","lineNumber":70,"sourceCode":"// Formats is the list of the supported formats.\nvar Formats = []FormatT{FormatCmd, FormatArgs, FormatOptions, FormatConfig}\n\nfunc quoteOption(o string) string {\n\t// make sure the shell doesn't swallow quotes in option values\n\tif strings.ContainsRune(o, '\"') {\n\t\to = \"'\" + o + \"'\"\n\t}\n\treturn o\n}\n\n// Format formats the ssh options.\nfunc Format(w io.Writer, sshPath, instName string, format FormatT, opts []string) error {\n\tfakeHostname := hostname.FromInstName(instName) // TODO: support customization\n\tfor _, o := range opts {\n\t\t// A line break in an option value (e.g. a crafted user.name) would inject\n\t\t// extra ssh_config directives such as ProxyCommand into the generated config.\n\t\tif strings.ContainsAny(o, \"\\r\\n\") {\n\t\t\treturn fmt.Errorf(\"ssh option %#q contains a line break\", o)\n\t\t}\n\t}\n\tswitch format {\n\tcase FormatCmd:\n\t\targs := []string{sshPath}\n\t\tfor _, o := range opts {\n\t\t\targs = append(args, \"-o\", quoteOption(o))\n\t\t}\n\t\targs = append(args, fakeHostname)\n\t\t// the args are similar to `limactl shell` but not exactly same. (e.g., lacks -t)\n\t\tfmt.Fprintln(w, strings.Join(args, \" \")) // no need to use shellescape.QuoteCommand\n\tcase FormatArgs:\n\t\tvar args []string\n\t\tfor _, o := range opts {\n\t\t\targs = append(args, \"-o\", quoteOption(o))\n\t\t}\n\t\tfmt.Fprintln(w, strings.Join(args, \" \")) // no need to use shellescape.QuoteCommand\n\tcase FormatOptions:","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/lima-vm/lima/blob/dd909d0973cd84fa35f9e1693181b4585ea616c1/pkg/sshutil/format.go#L52-L88","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nopts := []string{\"IdentityFile=\" + identity}\nsshutil.Format(w, sshPath, instName, sshutil.FormatConfig, opts)\n// after\nidentity = strings.ReplaceAll(identity, \"\\r\", \"\")\nidentity = strings.ReplaceAll(identity, \"\\n\", \" \")\nsshutil.Format(w, sshPath, instName, sshutil.FormatConfig, opts)","handlingStrategy":"validation","validationCode":"func hasLineBreak(opts []string) bool {\n    for _, o := range opts {\n        if strings.ContainsAny(o, \"\\r\\n\") {\n            return true\n        }\n    }\n    return false\n}\nif hasLineBreak(opts) { /* sanitize or reject before Format */ }","typeGuard":"func safeOption(o string) bool { return !strings.ContainsAny(o, \"\\r\\n\") }","tryCatchPattern":"if err := sshutil.Format(w, sshPath, instName, format, opts); err != nil {\n    if strings.Contains(err.Error(), \"contains a line break\") {\n        // sanitize opts and retry\n    }\n}","preventionTips":["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"],"tags":["ssh","input-validation","config-injection"],"backgroundTag":"ssh-config-injection","analyzedSha":"dd909d0973cd84fa35f9e1693181b4585ea616c1","analyzedAt":"2026-09-01T14:24:59.842Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}