HexBrain

curl · Report #3575245

Integer Overflow in curl_multi_get_handles() Leading to Heap Buffer Overflow

N/Astatus
mediumseverity
36upvotes
26 Feb 2026disclosed

How it was found

Integer Overflow in curl_multi_get_handles() Leading to Heap Buffer Overflow

Summary

The curl_multi_get_handles() function in lib/multi.c contains an integer overflow vulnerability when the number of easy handles in a multi handle approaches UINT_MAX (4,294,967,295). When count == UINT_MAX, the expression count + 1 overflows to 0, causing malloc(0) to return a non-NULL pointer. Subsequent write operations a[i++] = data then write beyond the allocated buffer, resulting in a heap buffer overflow. While exploitation requires extreme resource consumption (~32TB memory for ~4.3 billion handles), this represents a memory safety violation that should be addressed.

PoC Concept:

// lib/multi.c:3728-3729
unsigned int count = Curl_uint32_tbl_count(&multi->xfers);
CURL **a = curlx_malloc(sizeof(struct Curl_easy *) * (count + 1));  // OVERFLOW when count == UINT_MAX
// When count == 0xFFFFFFFF: count + 1 = 0, malloc(0) returns non-NULL
// Subsequent a[i++] = data writes to undersized buffer

Affected Version

curl version: 8.18.0 (API curl_multi_get_handles() introduced in this version)

Platform: All platforms (64-bit systems theoretically exploitable, 32-bit systems not exploitable due to address space limits)

curl 8.18.0 (x86_64-pc-linux-gnu) libcurl/8.18.0 OpenSSL/3.0.0 zlib/1.2.13
Release-Date: 2026-01-07
Protocols: dict file ftp ftps gopher gophers http https imap imaps ldap ldaps mqtt pop3 pop3s rtsp scp sftp smb smbs smtp smtps telnet tftp ws wss
Features: alt-svc AsynchDNS brotli GSS-API HSTS HTTP2 HTTP3 HTTPS-proxy IDN IPv6 Kerberos Largefile libz NTLM NTLM_WB PSL SPNEGO SSL TLS-SRP UnixSockets zstd

Steps to Reproduce

Method 1: Code Analysis (Recommended)

  1. Examine the vulnerable code in lib/multi.c:3724-3745:
CURL **curl_multi_get_handles(CURLM *m)
{
  struct Curl_multi *multi = m;
  void *entry;
  unsigned int count = Curl_uint32_tbl_count(&multi->xfers);
  CURL **a = curlx_malloc(sizeof(struct Curl_easy *) * (count + 1));  // VULNERABLE
  if(a) {
    unsigned int i = 0;
    uint32_t mid;
    if(Curl_uint32_tbl_first(&multi->xfers, &mid, &entry)) {
      do {
        struct Curl_easy *data = entry;
        DEBUGASSERT(i < count);
        if(!data->state.internal)
          a[i++] = data;  // Write to potentially undersized buffer
      } while(Curl_uint32_tbl_next(&multi->xfers, mid, &mid, &entry));
    }
    a[i] = NULL;
  }
  return a;
}
  1. Observe that when count == 0xFFFFFFFF (UINT_MAX):
    • count + 1 overflows to 0
    • malloc(sizeof(void*) * 0) = malloc(0) returns non-NULL
    • Subsequent writes cause heap buffer overflow

Method 2: Simulation PoC

Run the attached Python PoC to see the overflow demonstration:

# Simulate integer overflow
count = 0xFFFFFFFF  # UINT_MAX
overflow_result = (count + 1) & 0xFFFFFFFF  # Result: 0

# Memory allocation would be:
element_size = 8  # sizeof(void*) on 64-bit
alloc_size = element_size * overflow_result  # = 0 bytes
# malloc(0) returns non-NULL pointer

# Subsequent writes overflow the buffer

Method 3: Stress Test (Theoretical)

The following code demonstrates the attack path (not practical due to memory requirements):

#include <curl/curl.h>
#include <limits.h>

int main() {
    CURLM *multi = curl_multi_init();

    // Would need ~4.3 billion iterations
    // Requiring ~32TB of memory
    for(unsigned long i = 0; i < UINT_MAX; i++) {
        CURL *easy = curl_easy_init();
        curl_easy_setopt(easy, CURLOPT_URL, "http://example.com");
        curl_multi_add_handle(multi, easy);
    }

    // This triggers the overflow
    CURL **handles = curl_multi_get_handles(multi);
    // handles points to undersized buffer
    // Writing to handles[0] causes heap overflow

    return 0;
}

Impact

Security Impact

  1. Heap Buffer Overflow: When triggered, this vulnerability causes a write to memory beyond the allocated buffer boundary. This can lead to:

    • Memory corruption
    • Denial of Service (crash)
    • Potential arbitrary code execution (though exploitation is extremely difficult)
  2. Memory Safety Violation: This represents a fundamental violation of memory safety principles in a widely-used library.

Practical Exploitability

FactorAssessment
Memory Required~32TB (each handle ~8KB × 4.3 billion handles)
Time Required~50 days at 1,000 handles/sec
32-bit SystemsNot exploitable (4GB address space limit)
64-bit SystemsTheoretically exploitable but impractical
Real-world ImpactLOW - Extreme resource requirements make practical exploitation nearly impossible

Why This Still Matters

  1. Code Quality: This is a clear violation of secure coding practices (CWE-190: Integer Overflow)
  2. Future Risk: As memory becomes cheaper, the exploitability threshold may become more achievable
  3. Similar Patterns: This vulnerability pattern might exist in other parts of the codebase
  4. Defensive Programming: Adding the overflow check is a simple one-line fix that improves code robustness

Recommended Fix

unsigned int count = Curl_uint32_tbl_count(&multi->xfers);

/* Prevent integer overflow */
if(count == UINT_MAX) {
    return NULL;
}

CURL **a = curlx_malloc(sizeof(struct Curl_easy *) * (count + 1));

Attachments

  • curl_multi_overflow_poc.py - Python simulation demonstrating the overflow concept
  • curl_multi_overflow_poc.c - C PoC (requires libcurl)

Credit: Sun Tao Date: 2026-02-26

Impact

Summary:

The curl_multi_get_handles() function in lib/multi.c contains an integer overflow vulnerability when the number of easy handles in a multi handle approaches UINT_MAX (4,294,967,295). When count == UINT_MAX, the expression count + 1 overflows to 0, causing malloc(0) to return a non-NULL pointer. Subsequent write operations a[i++] = data then write beyond the allocated buffer, resulting in a heap buffer overflow. While exploitation requires extreme resource consumption (~32TB memory for ~4.3 billion handles), this represents a memory safety violation that should be addressed.

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