HexBrain

curl · Report #3508701

Use-After-Free in curl_easy_nextheader when reusing header handle across requests

Informativestatus
8upvotes
14 Jan 2026disclosed

How it was found

). The API returns struct curl_header objects that internally reference libcurl-owned linked list nodes. When a new request is performed on the same CURL* handle, libcurl frees and rebuilds the internal header list, but previously returned struct curl_header objects remain valid to the application and are still accepted as input.

Passing such a stale header object back to curl_easy_nextheader() causes libcurl to dereference a freed internal pointer, leading to a heap use-after-free.

This is a memory safety vulnerability reachable through normal API usage and attacker-controlled HTTP responses.

Affected Versions

All libcurl versions that include the Headers API (curl_easy_header, curl_easy_nextheader)

Reproduced on:

Kali Linux libcurl (January 2026)

Likely all current supported versions

File: lib/headers.c

Technical Analysis Vulnerable Design

curl_easy_nextheader() exposes struct curl_header to the application:

struct curl_header { const char *name; const char *value; unsigned int amount; unsigned int index; unsigned int origin; void anchor; / internal Curl_llist_node */ };

The anchor field stores a pointer to libcurl’s internal linked list node:

copy_header_external(..., struct Curl_llist_node *e, ...) { h->anchor = e; }

Later, when a new request is performed, libcurl frees the internal header list:

Curl_headers_cleanup(struct Curl_easy *data) { for(e = Curl_llist_head(&data->state.httphdrs); e; e = n) { struct Curl_header_store *hs = Curl_node_elem(e); curlx_free(hs); } }

However, previously returned struct curl_header objects remain valid in user code and can still be passed back to:

curl_easy_nextheader(CURL *easy, unsigned int type, int request, struct curl_header *prev)

This function blindly dereferences:

pick = prev->anchor; pick = Curl_node_next(pick);

If the header list has been freed and rebuilt, prev->anchor now points to freed heap memory → use-after-free.

There is:

No invalidation of old struct curl_header

No generation tracking

No lifetime enforcement

The API contract does not state that header handles become invalid after a new request.

Proof of Concept #include <stdio.h> #include <curl/curl.h>

int main(void) { CURL *curl = curl_easy_init(); if(!curl) return 1;

struct curl_header *h = NULL;

/* First request */ curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/"); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_perform(curl);

/* Obtain and store a header */ h = curl_easy_nextheader(curl, CURLH_HEADER, -1, NULL); printf("saved header: %s: %s\n", h->name, h->value);

/* Second request (frees and rebuilds internal header list) */ curl_easy_setopt(curl, CURLOPT_URL, "https://httpbin.org/get"); curl_easy_perform(curl);

/* Reuse stale header handle */ printf("calling nextheader with stale prev...\n"); struct curl_header *h2 = curl_easy_nextheader(curl, CURLH_HEADER, -1, h); if(h2) printf("next header: %s: %s\n", h2->name, h2->value);

curl_easy_cleanup(curl); return 0; }

Build and Run gcc -fsanitize=address -g poc.c -lcurl -o poc ./poc

ASAN Output (Excerpt) ERROR: AddressSanitizer: heap-use-after-free READ of size 13 freed by: libcurl.so Curl_headers_cleanup allocated by: libcurl.so Curl_headers_push

This confirms that curl_easy_nextheader() dereferences freed memory.

Impact

Security Impact

A malicious HTTP server can influence response headers and trigger a heap use-after-free in applications using libcurl’s Headers API when multiple requests are performed on the same CURL* handle.

This can lead to:

Process crash (Denial of Service)

Heap memory corruption

Potential code execution depending on allocator state and surrounding memory

The vulnerability:

Is reachable through documented public API

Is triggered by attacker-controlled HTTP responses

Does not require MITM

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