{"record":{"id":"2cf4e1d6d9c125c1","repo":"shadow1ng/fscan","slug":"credential-contains-line-break","errorCode":null,"errorMessage":"credential contains line break","messagePattern":"credential contains line break","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugins/services/text_protocol.go","lineNumber":18,"sourceCode":"//go:build !plugin_selective || plugin_activemq || plugin_imap || plugin_pop3 || plugin_redis\n\npackage services\n\nimport (\n\t\"fmt\"\n\t\"strconv\"\n\t\"strings\"\n)\n\nfunc hasLineBreak(s string) bool {\n\treturn strings.ContainsAny(s, \"\\r\\n\")\n}\n\nfunc rejectLineBreaks(values ...string) error {\n\tfor _, value := range values {\n\t\tif hasLineBreak(value) {\n\t\t\treturn fmt.Errorf(\"credential contains line break\")\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc imapQuotedString(s string) (string, error) {\n\tif hasLineBreak(s) {\n\t\treturn \"\", fmt.Errorf(\"imap credential contains line break\")\n\t}\n\treturn strconv.Quote(s), nil\n}\n\nfunc buildIMAPLoginCommand(tag, username, password string) (string, error) {\n\tquotedUser, err := imapQuotedString(username)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tquotedPass, err := imapQuotedString(password)","sourceCodeStart":1,"sourceCodeEnd":36,"githubUrl":"https://github.com/shadow1ng/fscan/blob/95cc12e753bf43de7004e5aef42a9ffba3934303/plugins/services/text_protocol.go#L1-L36","documentation":"A defensive injection guard: text-protocol credentials (STOMP, IMAP-adjacent login helpers) are scanned for CR/LF and rejected because a line break would let an attacker inject extra protocol commands (CRLF injection). rejectLineBreaks returns this plain (non-i18n) error if any supplied value contains \\r or \\n.","triggerScenarios":"Calling authenticateSTOMP or tryLogin with a username or password containing '\\n' or '\\r', typically from untrusted input such as a config file, environment variable, or scan target list.","commonSituations":"Credentials read from files without trimming trailing newlines (e.g. password read via scanner including '\\n'); YAML/JSON configs with embedded newlines; intentionally malicious inputs during testing.","solutions":["Trim CR/LF from credential values before calling the authenticate functions.","Validate credentials at load time and reject any containing line breaks.","Fix the source (config parser/file reader) so values are read without trailing newlines.","Keep the guard in place — do not bypass it, since it prevents protocol injection."],"exampleFix":"// before\npassword := strings.TrimSpace(string(data)) // may still embed internal \\n\nerr := tryLogin(conn, user, password)\n// after\nif strings.ContainsAny(password, \"\\r\\n\") {\n    return fmt.Errorf(\"credential contains line break\")\n}\nerr := tryLogin(conn, user, password)","handlingStrategy":"validation","validationCode":"if strings.ContainsAny(username, \"\\r\\n\") || strings.ContainsAny(password, \"\\r\\n\") {\n    return errors.New(\"credential contains line break\")\n}","typeGuard":"func safeCredential(s string) bool { return s != \"\" && !strings.ContainsAny(s, \"\\r\\n\") }","tryCatchPattern":"if err := rejectLineBreaks(user, pass); err != nil {\n    // sanitize or reject the credential before sending to the protocol\n}","preventionTips":["Trim credentials read from files/configs","Validate credentials at load time, before use","Never pass raw user input into protocol login helpers","Keep injection guards enabled in production paths"],"tags":["injection","validation","text-protocol"],"backgroundTag":"invalid-argument-value","analyzedSha":"95cc12e753bf43de7004e5aef42a9ffba3934303","analyzedAt":"2026-09-06T17:07:30.094Z","contentChangedAt":"2026-09-06T17:07:30.094Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}