Mon, 26 Mar 2007


The mail() function converts control characters like linefeed or carriage return in the Subject and To parameters into spaces as a protection against email header injection. However an exception is made for folded mail headers that continue on the next line. Unfortunately the macro handling this folding is flawed and can be tricked to allow email header injection.

Affected versions

Affected are PHP 4 <= 4.4.6 and PHP 5 <= 5.2.1

Detailed information

The mail() function contains the following code supposed to handle folded email headers. The macro was expanded to allow for better readability.

for(i = 0; subject_r[i]; i++) {
   if (iscntrl((unsigned char) subject_r[i])) {
      //SKIP_LONG_HEADER_SEP(subject_r, i);
      if (str[pos] == '\r' && str[pos + 1] == '\n' && (str[pos + 2] == ' ' || str[pos + 2] == '\t')) {
         pos += 3;
         while (str[pos] == ' ' || str[pos] == '\t') {
      subject_r[i] = ' ';

The idea of the SKIP_LONG_HEADER_SEP macro is to detect folded header lines and do not overwrite the linefeed and carriage return with a space character. Unfortunately there is an obvious flaw in the way this is done. When the folding is immediately followed by a control character (like a linefeed or carriage return) it will not get replaced with space, because the continue command will wrongly increase the loop counter i. Therefore it is possible to inject a newline with a simple sequence like \r\n\t\n.

This injection is possible with both the Subject and the To parameter. During our tests we realised that exim seems to have problems with newline injection in the To header, while good old sendmail handled it perfectly.

Proof of concept, exploit or instructions to reproduce

A simple test for this vulnerability is the following PHP script:

   mail("test@domain(dot)com", "Test\r\n \nAnother-Header: Blub", "Message");


In articles about email injection one usually only reads about header injection in the additional header parameter. Unfortunately this and the previous vulnerability proof that all parameters of the mail() function are suspect to email injection problems.