CVE-2017-1000257

The Zero-Byte Betrayal: Inside libcurl's IMAP Buffer Over-read

Amit Schendel
Amit Schendel
Senior Security Researcher

Jan 10, 2026·5 min read

Executive Summary (TL;DR)

libcurl treated a data size of '0' as a magic number instructing it to calculate string length automatically using `strlen()`. When processing IMAP `FETCH` responses indicating zero bytes of data, this logic fired on a raw network buffer, causing libcurl to read past the end of the buffer until it hit a null byte. This results in an out-of-bounds read, leaking heap memory to the application or causing a crash.

A critical buffer over-read vulnerability in libcurl's IMAP handler where receiving a zero-byte data indicator triggers an unsafe `strlen()` call on a non-null-terminated heap buffer. This flaw allows malicious servers to crash clients or extract sensitive data from the client's process memory.

The Hook: When 0 Means Infinity

In the world of C programming, API design is often a minefield of historical debt and 'clever' shortcuts. One of the most dangerous patterns is the "Magic Number"—assigning a special behavior to a specific integer value. Usually, -1 means error, 0 means success or empty. But in the bowels of libcurl, specifically within its generic data writing logic, 0 held a much darker secret.

libcurl is the Swiss Army knife of network transfer, embedded in everything from cars to fridges to your favorite operating system. It speaks dozens of protocols, including the ancient and verbose IMAP (Internet Message Access Protocol). IMAP is a chatty protocol where the server tells the client exactly how many bytes of email data to expect.

This vulnerability, discovered by Brian Carpenter and 0xd34db347 (and independently by OSS-Fuzz), is a masterclass in why defensive coding matters. It wasn't a complex heap feng-shui exploit. It was a simple misunderstanding between the IMAP protocol handler and the core data writing function. The handler said "I have zero bytes," and the writer heard "Count the bytes yourself until you crash."

The Flaw: The Ambiguity of Zero

The vulnerability resides in how libcurl processes the IMAP FETCH command. When a client requests an email body, the server responds with the size of the data in bytes. For example, {100} means 100 bytes follow. The code in imap_state_fetch_resp parses this number into a variable called chunk.

If a malicious (or broken) server responds with {0}, chunk becomes 0. The code then calls Curl_client_write(conn, CLIENTWRITE_BODY, pp->cache, chunk). This seems harmless. Writing 0 bytes should be a no-op, right? It's like asking a waiter for zero glasses of water.

However, Curl_client_write is designed to be helpful. Too helpful. Deep inside its logic, it interprets a size argument of 0 not as "write nothing," but as "I don't know the size, please run strlen() on the pointer to find out." This is a catastrophic assumption when dealing with network protocols.

pp->cache points to a raw network buffer on the heap. It is not guaranteed to be a null-terminated C-string at that exact offset. It contains whatever raw bytes came off the wire. When strlen() executes, it ignores the buffer boundaries and marches happily across the heap, reading byte after byte until it coincidentally finds a 0x00 byte. This is a classic Buffer Over-read.

The Code: The Smoking Gun

Let's look at the vulnerable logic in lib/imap.c before the patch. The code parses the size, casts it to size_t, and immediately passes it to the writer without validation.

/* lib/imap.c (Vulnerable) */
 
/* Parse the size from the server response */
if(sscanf(ptr, "%" CURL_FORMAT_CURL_OFF_T, &size) == 1) {
    /* ... checks ... */
    
    chunk = (size_t)size;
    
    /* FATAL FLAW: Passing chunk=0 into this function */
    result = Curl_client_write(conn, CLIENTWRITE_BODY, pp->cache, chunk);
    if(result)
      return result;
}

The fix is ridiculously simple. It forces the IMAP handler to explicitly check for the zero case and handle it before invoking the generic writer. This prevents the "magic number" logic from ever triggering.

/* lib/imap.c (Patched in 7.56.1) */
 
chunk = (size_t)size;
 
/* The Fix: Explicitly handle zero-length data */
if(!chunk) {
  /* no size, we're done with the data */
  state(conn, IMAP_STOP);
  return CURLE_OK;
}
 
result = Curl_client_write(conn, CLIENTWRITE_BODY, pp->cache, chunk);

This small if(!chunk) block saves the library from reading undefined memory. It stops the propagation of the "0" value into the dangerous Curl_client_write API.

The Exploit: Leaking the Heap

Exploiting this requires a client to connect to a malicious IMAP server. This could be achieved via a Man-in-the-Middle (MitM) attack or by social engineering a user/application to connect to an attacker-controlled endpoint.

Here is the attack flow:

  1. Setup: Attacker runs a Python script binding to port 143 (IMAP).
  2. Connection: The victim's application (using a vulnerable libcurl) connects.
  3. Handshake: The server completes the capability negotiation and login sequence normally.
  4. The Trigger: When the client issues a FETCH command (e.g., trying to download an email), the server sends a crafted response: * 1 FETCH (BODY[] {0}

This {0} is the weapon. libcurl parses it, calls the writer with size 0, and strlen() takes over.

The Payoff: libcurl reads beyond the network buffer. It takes whatever data is adjacent in the heap—SSL private keys, authentication tokens, HTTP headers from previous requests—and treats it as the "email body." This data is then returned to the calling application. If the application saves the email to disk or displays it, the attacker (or the user) sees the leaked secrets.

The Impact: Why This Matters

While this is "only" a read and not a write (making Remote Code Execution unlikely directly via this bug), the impact is severe due to the context of libcurl usage.

Information Disclosure: In a multi-threaded application or one that reuses CURL handles, the heap is a shared resource. The memory immediately following the IMAP buffer could contain sensitive data from other threads or previous connections. Imagine a PHP server using libcurl to fetch mail; a crash is annoying, but leaking the session ID of a purely unrelated user is a critical breach.

Denial of Service: If the strlen() scan doesn't encounter a null byte before hitting an unmapped memory page, the application will segfault immediately. For critical infrastructure relying on libcurl for automated reporting, a malicious server could keep the service permanently offline.

Fix Analysis (1)

Technical Appendix

CVSS Score
9.1/ 10
CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
EPSS Probability
1.09%
Top 23% most exploited

Affected Systems

libcurl 7.20.0 through 7.56.0

Affected Versions Detail

Product
Affected Versions
Fixed Version
libcurl
haxx.se
>= 7.20.0, <= 7.56.07.56.1
AttributeDetail
CWECWE-126 (Buffer Over-read)
CVSS v3.09.1 (Critical)
Attack VectorNetwork
PrivilegesNone
EPSS Score1.09%
Patch Commit13c9a9d
CWE-126
Buffer Over-read

The software reads from a buffer using a length parameter that is not consistent with the size of the buffer, specifically reading past the boundary.

Vulnerability Timeline

Reported by Brian Carpenter and 0xd34db347
2017-10-06
Detected by OSS-Fuzz
2017-10-08
Patch Released (v7.56.1)
2017-10-23
CVE Published
2017-10-31

Subscribe to updates

Get the latest CVE analysis reports delivered to your inbox.