{"record":{"id":"b87e258794055ec7","repo":"eclipse-vertx/vert.x","slug":"only-n-is-allowed-after-r-seq","errorCode":null,"errorMessage":"only '\\n' is allowed after '\\r': <seq>","messagePattern":"only '\\\\n' is allowed after '\\\\r': <seq>","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"vertx-core/src/main/java/io/vertx/core/http/impl/HttpUtils.java","lineNumber":763,"sourceCode":"        }\n        return NO_CR_LF_STATE;\n      }\n    }\n    if (state != NO_CR_LF_STATE) {\n      // this is a rare scenario\n      return validateCrLfChar(seq, state, ch);\n    } else {\n      return NO_CR_LF_STATE;\n    }\n  }\n\n  private static int validateCrLfChar(CharSequence seq, int state, char ch) {\n    switch (state) {\n      case CR_STATE:\n        if (ch == '\\n') {\n          return LF_STATE;\n        }\n        throw new IllegalArgumentException(\"only '\\\\n' is allowed after '\\\\r': \" + seq);\n      case LF_STATE:\n        switch (ch) {\n          case '\\t':\n          case ' ':\n            // return to the normal state\n            return NO_CR_LF_STATE;\n          default:\n            throw new IllegalArgumentException(\"only ' ' and '\\\\t' are allowed after '\\\\n': \" + seq);\n        }\n      default:\n        // this should never happen\n        throw new AssertionError();\n    }\n  }\n\n  private static void validateNonPrintableCtrlChar(CharSequence seq, int ch) {\n    // The only characters allowed in the range 0x00-0x1F are : HTAB, LF and CR\n    switch (ch) {","sourceCodeStart":745,"sourceCodeEnd":781,"githubUrl":"https://github.com/eclipse-vertx/vert.x/blob/fb308bd8c3f12c79f4ae89bef67fadf6c80d036e/vertx-core/src/main/java/io/vertx/core/http/impl/HttpUtils.java#L745-L781","documentation":"Vert.x validates HTTP header values to prevent header smuggling and malformed framing. When a header value contains a carriage return ('\\r') that is not immediately followed by a line feed ('\\n') — i.e. a bare CR — this IllegalArgumentException is thrown. Bare CR is not a legal line terminator in HTTP header values and can be used to inject headers.","triggerScenarios":"Calling request.putHeader(name, value) / HttpHeaders.set or any API that writes a header whose value contains a '\\r' character that is not directly followed by '\\n' (e.g. \"a\\rb\", \"a\\r\\tb\"), triggered during header validation in HttpUtils.validateValueChar/validateSequenceHeaderValue.","commonSituations":"Building header values by joining multi-line data with '\\r' line endings (e.g. Windows-style text or log data); copying a header value captured from raw CRLF-split bytes; template strings pasted from Windows editors that embedded CR characters.","solutions":["Remove or replace bare '\\r' characters from the header value (use '\\n' only inside obs-fold sequences, or better, strip all line breaks).","Sanitize the value before setting it, e.g. value.replaceAll(\"[\\\\r\\\\n]\", \" \").","If obs-fold is intended, ensure the sequence is exactly CRLF followed by SP or HTAB (\"\\r\\n \")."],"exampleFix":"// before\nrequest.putHeader(\"X-Note\", \"line1\\rline2\"); // throws\n// after\nrequest.putHeader(\"X-Note\", \"line1\\nline2\".replace(\"\\r\", \"\")); // or replace line breaks with spaces","handlingStrategy":"validation","validationCode":"public static void checkHeaderNoBareCr(String name, String value) {\n  for (int i = 0; i < value.length(); i++) {\n    if (value.charAt(i) == '\\r' && (i + 1 >= value.length() || value.charAt(i + 1) != '\\n')) {\n      throw new IllegalArgumentException(\"bare CR in header \" + name);\n    }\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  request.putHeader(name, value);\n} catch (IllegalArgumentException e) {\n  log.warn(\"Rejecting header {} : {}\", name, e.getMessage());\n  request.putHeader(name, sanitize(value));\n}","preventionTips":["Sanitize all header values with a strip-CR/LF helper before setting them","Never embed raw text from Windows-sourced data or logs directly into header values","Treat any '\\r' in dynamic input as a header-injection attempt and reject it upstream"],"tags":["http","headers","validation","vertx"],"backgroundTag":"invalid-argument-value","analyzedSha":"fb308bd8c3f12c79f4ae89bef67fadf6c80d036e","analyzedAt":"2026-09-06T11:37:12.241Z","contentChangedAt":"2026-09-06T11:37:12.241Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}