Glossary

CRLF

CRLF stands for Carriage Return plus Line Feed, the two-byte line ending 0x0D 0x0A, written \r\n in most programming languages. Network protocols such as HTTP/1.1 and email require it, while Unix-style text files end lines with a bare LF, 0x0A.

How it works

CR is byte 13 (0x0D) and LF is byte 10 (0x0A) in ASCII. RFC 5234, the ABNF grammar standard, defines the rule CRLF = CR LF, and most Internet specifications reuse it.

  • HTTP/1.1: RFC 9112 ends the start line and every header field line with CRLF, and a blank line (another CRLF) ends the header section. A recipient may accept a bare LF as a line terminator. A sender must not send a bare CR.
  • Email: RFC 5322 caps each line at 998 characters, with 78 recommended, both counted without the CRLF.
  • CSV: RFC 4180 separates records with CRLF, and the last record may omit it.
  • Text files: Linux text files use LF, and Node's os.EOL and PHP's PHP_EOL are both a bare LF there. A file saved with CRLF endings differs from its LF twin on every line.
printf 'GET / HTTP/1.1\r\nHost: example.com\r\n\r\n' | od -An -c
printf 'a\r\nb\r\n' | wc -c
printf 'a\r\nb\r\n' | tr -d '\r' | wc -c

Output from a real run:

   G   E   T       /       H   T   T   P   /   1   .   1  \r  \n
   H   o   s   t   :       e   x   a   m   p   l   e   .   c   o
   m  \r  \n  \r  \n
6
4

The request is 37 bytes in total. The final blank line is nothing more than a second CRLF pair, and it is what tells the server the header section is over.

What is the difference between CRLF and LF?

CRLF is two bytes (0x0D 0x0A) and LF is one byte (0x0A). Each line break in a CRLF file costs one extra byte, so the 4 characters "a", newline, "b", newline take 4 bytes with LF and 6 with CRLF. The difference is easy to miss, but a plain diff of the two files reports every line as changed, and a script that splits on LF alone gets 'a\r' and 'b\r'.

What is CRLF injection?

CRLF injection is an attack where untrusted input containing CR and LF is written into an HTTP header, letting the attacker end the header early and add headers or a second response. RFC 9112 section 11.1 calls it response splitting. The defense is to let the HTTP library write headers and reject CR or LF in values. Node.js does this: setHeader with a value containing a line break throws ERR_INVALID_CHAR with the message "Invalid character in header content".

Common pitfalls

  • Splitting on "\n" only: a CRLF file leaves a trailing "\r" on every line, so comparisons fail silently. Split on the pattern \r?\n, or in Python open the file in text mode, which turns \r\n into \n on read.
  • Git line-ending warnings: with core.autocrlf set to true, adding an LF file prints "LF will be replaced by CRLF the next time Git touches it".
  • Echoing user input into headers: a redirect that copies a query parameter into the Location header without filtering CR and LF is the textbook response-splitting bug.
  • Hard-coding "\n" in protocol code: RFC 9112 lets a recipient accept a bare LF but does not require it, so a client that sends LF alone depends on a lenient server. Send CRLF.
  • Counting characters: the 998 and 78 limits in RFC 5322 exclude the CRLF, and in JavaScript 'a\r\n'.length is 3 because CR and LF count separately.

Related terms

  • ASCII — defines CR as 13 and LF as 10
  • HTTP — ends every header line with CRLF
  • CSV — separates records with CRLF per RFC 4180
  • Git — converts line endings with core.autocrlf
  • URL encoding — writes CR and LF as %0D and %0A

See also

  • Tool: Text Diff Checker — compares two text blocks and highlights added, removed and changed lines