# Disallow newlines in CURLOPT_HTTPHEADER

- Thread: https://externals.io/message/131826
- Original archive: https://news-web.php.net/php.internals/131826
- Started by Sjoerd Langkemper on 2026-07-09T08:17:20+00:00
- Messages: 15
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · RFCs at https://externals.io/rfc.md · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #131826 — Sjoerd Langkemper — 2026-07-09T08:17:20+00:00

URL: https://externals.io/message/131826#131826

Hello,

Currently, it is possible to have multiple lines in a HTTP headers in a cURL request, which then get interpreted as multiple headers:

$ch = curl_init('https://httpbin.dev/headers');
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Hello: world\r\nFoo: bar"]);
curl_exec($ch);

This sends two headers to the server (even when using HTTP/2):

{
  "headers": {
   ...
    "Foo": [
      "bar"
    ],
    "Hello": [
      "world"
    ],
  }
}

This is not supported behavior by cURL, and it is a security risk when a header value is under control of an attacker: they can inject arbitrary headers to the request.

I propose to not allow newlines in header values. Any thoughts on this? Should this first raise a deprecation warning before throwing a value error? I haven't added this to the deprecation RFC as I thought that is being finalized and made ready for voting soon.

Regards,

Sjoerd Langkemper

---

## #131828 — tim@bastelstu.be — 2026-07-09T08:53:38+00:00

URL: https://externals.io/message/131826#131828 · In reply to: #131826

Hi


> Currently, it is possible to have multiple lines in a HTTP headers in a 
> cURL request, which then get interpreted as multiple headers:
> 
> […]
> 
> This is not supported behavior by cURL, and it is a security risk when 
> a header value is under control of an attacker: they can inject 
> arbitrary headers to the request.
> 
> I propose to not allow newlines in header values. Any thoughts on this? 
> Should this first raise a deprecation warning before throwing a value 
> error? I haven't added this to the deprecation RFC as I thought that is 
> being finalized and made ready for voting soon.

Ugh. I agree that this is unexpected behavior that enables security 
issues and would suggest going straight to ValueError with PHP 8.6. 
Since `CURLOPT_HTTPHEADER` already rejects string inputs:

     curl_setopt($ch, CURLOPT_HTTPHEADER, "Hello: world\r\nFoo: bar");

the API already very heavily implies that you are expected to pass 
headers as individual array elements - and it's also documented that 
way. Thus I would say this falls under the rules in 
https://wiki.php.net/rfc/policy-exempt-type-value-error-bc-policy.

Can you send a PR?

Best regards
Tim Düsterhus

---

## #131832 — Craig Francis — 2026-07-09T10:29:21+00:00

URL: https://externals.io/message/131826#131832 · In reply to: #131826

On Thu, 9 Jul 2026 at 09:21, Sjoerd Langkemper <sjoerd-php@linuxonly.nl>
wrote:

> I propose to not allow newlines in header values. Any thoughts on
> this? Should this first raise a deprecation warning before throwing a value
> error?
>


Thanks for noticing this, while header injection vulnerabilities aren't
that common, it's still a problem.

I just wanted to note that the `header()` function rejects newlines (since
5.1.2):

header("Hello: world\r\nFoo: bar");


Warning: Header may not contain more than a single header, new line
detected in [...]

The header is simply not sent.

https://github.com/php/php-src/blob/9dc29aafa5eecc71a9f9e2c7607b588597a91810/main/SAPI.c#L760

https://github.com/php/php-src/commit/f2415625d4848b503f1fbcc7986211d6eb4aa7df

Craig

---

## #131833 — Matteo Beccati — 2026-07-09T10:49:35+00:00

URL: https://externals.io/message/131826#131833 · In reply to: #131826

Hi,

Il 09/07/2026 10:17, Sjoerd Langkemper ha scritto:
> This is not supported behavior by cURL, and it is a security risk when a 
> header value is under control of an attacker: they can inject arbitrary 
> headers to the request.
> 
> I propose to not allow newlines in header values. Any thoughts on 
> this? Should this first raise a deprecation warning before throwing a 
> value error? I haven't added this to the deprecation RFC as I thought 
> that is being finalized and made ready for voting soon.

"\r\n" inside headers used to be perfectly legal for multiline headers.

It is now obsolete, but I'm not sure why we should prevent it, if curl 
does not.

See:
https://www.rfc-editor.org/info/rfc9112/#name-obsolete-line-folding


Cheers
-- 
Matteo Beccati

---

## #131834 — Matteo Beccati — 2026-07-09T11:01:34+00:00

URL: https://externals.io/message/131826#131834 · In reply to: #131833

Il 09/07/2026 12:49, Matteo Beccati ha scritto:
> "\r\n" inside headers used to be perfectly legal for multiline headers.
> 
> It is now obsolete, but I'm not sure why we should prevent it, if curl 
> does not.
> 
> See:
> https://www.rfc-editor.org/info/rfc9112/#name-obsolete-line-folding
Apologies, I forgot the code example:

curl_setopt($ch, CURLOPT_HTTPHEADER, ["x-foo: foo\r\n bar"]);

Tested on Apache + php 8.1:

var_dump($_SERVER['HTTP_X_FOO']) happily returns: string(7) "foo bar"


I haven't tested other configurations.


Cheers
-- 
Matteo Beccati

---

## #131835 — tim@bastelstu.be — 2026-07-09T11:10:02+00:00

URL: https://externals.io/message/131826#131835 · In reply to: #131833

Hi


> Il 09/07/2026 10:17, Sjoerd Langkemper ha scritto:
> > […]
> 
> "\r\n" inside headers used to be perfectly legal for multiline headers.

This is not correct. What was legal was the sequence "\r\n" followed *by 
either a space or a tab*. And it is equivalent to just a space. The 
newlines are not “visible” in the parsed value. There is literally zero 
reason to emit the obsolete line-folding syntax nowadays. As far as I 
can tell it only existed due to considerations regarding the length of a 
single line.

> It is now obsolete, but I'm not sure why we should prevent it, if curl 
> does not.

Curl specifically documents:

> The headers included in the linked list must not be CRLF-terminated, 
> since libcurl adds CRLF after each header item itself. Failure to 
> comply with this might result in strange behavior. libcurl passes on 
> the verbatim strings you give it, without any filter or other safe 
> guards. That includes white space and control characters.

Best regards
Tim Düsterhus

---

## #131836 — Matteo Beccati — 2026-07-09T11:23:58+00:00

URL: https://externals.io/message/131826#131836 · In reply to: #131835

Hi Tim,

Il 09/07/2026 13:10, Tim Düsterhus ha scritto:
> Hi
> 
> 
> > […]
> 
> This is not correct. What was legal was the sequence "\r\n" followed *by 
> either a space or a tab*. And it is equivalent to just a space. The 
> newlines are not “visible” in the parsed value. There is literally zero 
> reason to emit the obsolete line-folding syntax nowadays. As far as I 
> can tell it only existed due to considerations regarding the length of a 
> single line.

Yes, that's precisely my point. "\r\n" followed by a space or tab used 
to be a thing. Yes, it is obsolete, but for whatever reason I might be 
required to test that specific scenario using curl.


> Curl specifically documents:
> 
> > […]
Yes, and that seems to be a design choice from the curl team, that we 
might want to respect.

Blocking "\r\n" would be perfectly fine in a userland HTTP Client before 
calling `curl_setopt()`.


Cheers
-- 
Matteo Beccati

---

## #131841 — Sjoerd Langkemper — 2026-07-09T13:38:18+00:00

URL: https://externals.io/message/131826#131841 · In reply to: #131835

Sjoerd Langkemper ha scritto:
> > […]

I started on the implementation for this: https://github.com/php/php-src/pull/22651. Besides checking for newlines, it also throws an error on NUL bytes.

> Curl specifically documents:
> 
> > […]

This documentation is not totally accurate. With HTTP/2 you could technically send a header with newlines in it, but cURL still splits a value with newlines into multiple headers. So it does not pass on "the verbatim strings you give it".

cURL doesn't do input validation regarding this, but documents that you should not call it with newlines in headers. So I think it makes sense to check for that in PHP.

I also understand Matteo's point that this breaks the hypothetical legitimate use of newlines in headers, but even so I would prefer throwing a value error on headers with newlines.

So this probably needs an RFC?

Regards,

Sjoerd

---

## #131843 — Jorg Sowa — 2026-07-09T16:07:56+00:00

URL: https://externals.io/message/131826#131843 · In reply to: #131841

Hey Sjoerd,
While this would be a useful improvement, it introduces BC concerns. I
would prefer to see this change go through a deprecation phase first, so we
can avoid unexpectedly breaking existing user implementations.

Kind regards,
Jorg

---

## #131880 — Sjoerd Langkemper — 2026-07-13T11:00:38+00:00

URL: https://externals.io/message/131826#131880 · In reply to: #131843

> While [rejecting newlines in cURL headers] would be a useful improvement, it introduces BC concerns. I would prefer to see this change go through a deprecation phase first, so we can avoid unexpectedly breaking existing user implementations.

Thank you for your feedback. It seems to me that this is exactly a case where this policy applies: https://wiki.php.net/rfc/policy-exempt-type-value-error-bc-policy

I asked Daniel Stenberg about whether newlines are allowed in headers, and he said:

> The documentation says in clear terms:
> 
>    The headers included in the linked list must not be CRLF-terminated
> 
> I believe libcurl might change its treatment of them in a future and start 
> returning error earlier when such octets are found.

Regards,

Sjoerd

---

## #131882 — tim@bastelstu.be — 2026-07-13T13:27:17+00:00

URL: https://externals.io/message/131826#131882 · In reply to: #131880

Hi


> I asked Daniel Stenberg about whether newlines are allowed in headers, 
> and he said:
> 
> > […]

Thank you. Did you ask in any publicly logged location (i.e. not IRC) so 
that you can provide a link for reference?

Though I'm also seeing https://github.com/curl/curl/pull/22309, which I 
think concludes the question.

Best regards
Tim Düsterhus

---

## #131902 — Sjoerd Langkemper — 2026-07-13T18:32:38+00:00

URL: https://externals.io/message/131826#131902 · In reply to: #131882

> Though I'm also seeing https://github.com/curl/curl/pull/22309, which I 
> think concludes the question.
Interesting, thanks. That PR adds a check for newlines in curl. So that makes it clear that headers are really not supposed to have newlines. But if curl checks this perhaps a check in PHP is not really adding anything. It could offer better error messages, and include the check even when someone is using an older curl. Would it still be valuable to include the newline check in PHP?

> > […]
> Did you ask in any publicly logged location so 
> that you can provide a link for reference?
No. I emailed him.

Regards,

Sjoerd

---

## #131909 — tim@bastelstu.be — 2026-07-14T08:13:33+00:00

URL: https://externals.io/message/131826#131909 · In reply to: #131902

Hi


> Interesting, thanks. That PR adds a check for newlines in curl. So that 
> makes it clear that headers are really not supposed to have newlines. 
> But if curl checks this perhaps a check in PHP is not really adding 
> anything. It could offer better error messages, and include the check 
> even when someone is using an older curl. Would it still be valuable to 
> include the newline check in PHP?

It will be a while until that cURL version makes it into the various 
operating systems. Including an extra check in PHP for improved error 
messages and consistent behavior makes sense to me, it's not uncommon to 
run newer PHP versions on older OS versions (e.g. within Docker).

Best regards
Tim Düsterhus

---

## #132106 — Sjoerd Langkemper — 2026-07-27T09:21:10+00:00

URL: https://externals.io/message/131826#132106 · In reply to: #131882

Hi Jorg, Matteo,

I wrote earlier:
> It seems to me that this is exactly a case where this policy applies: https://wiki.php.net/rfc/policy-exempt-type-value-error-bc-policy

and:
> I asked Daniel Stenberg about whether newlines are allowed in headers, 
> and he said:
>  
> > […]


> Though I'm also seeing https://github.com/curl/curl/pull/22309, which I 
> think concludes the question.

Given that Daniel Stenberg has said that newlines are not permitted, and is currently developing a pull request to reject them, does this change your view on whether PHP should reject newlines in headers passed to curl? Do you think I still need an RFC for this functionality?

Regards,

Sjoerd Langkemper

---

## #132107 — Matteo Beccati — 2026-07-27T10:12:40+00:00

URL: https://externals.io/message/131826#132107 · In reply to: #132106

Hi Sjoerd,


> Given that Daniel Stenberg has said that newlines are not permitted, and is currently developing a pull request to reject them, does this change your view on whether PHP should reject newlines in headers passed to curl? Do you think I still need an RFC for this functionality?

My point of view is that libcurl will eventually take care of it. No pressing need to do anything on our side.


Cheers
-- 
Matteo Beccati
