Integer Overflow to Heap Overflow in DoH Response Handling
What the report claims
An integer overflow in the multiplication of size and nmemb within the doh_probe_write_cb function leads to a heap overflow when processing DoH responses.
Compare with curl's recorded outcome
Labeled AI slop
curl's maintainer lists this report as AI slop
Shown for comparison after analysis. The pipeline did not see this label.
ProveIt's finding
The code provides evidence against the report's central claim. Review the cited lines before deciding.
curl policy: NULL dereferences and crashesWhy this finding?
- The write callback parameters size and nmemb are controlled by libcurl, not the server; libcurl calls use size=1 and nmemb bounded by the receive buffer (~16KB), making overflow impossible.
- The dynbuf for DoH responses has a hard limit (toobig=3000) that rejects any write larger than 2999 bytes with CURLE_TOO_LARGE before allocation.
- The PoC uses artificial parameters (nmemb=SIZE_MAX) that a server cannot cause, and even then the toobig check would prevent a crash.
- Project policy explicitly states that server-triggered crashes without further consequence are not considered security issues.
How this analysis ran 5 claims · 3 citations verified
Checked against curl master on 2025-10-25 (c59bf9018633). Test evaluation split. Citation verification checks that a referenced line was in the evidence; it does not prove the model interpreted it correctly.
Review a draft reply to the reporter
Edit and verify before sending.
Thank you for the report. The integer multiplication in doh_probe_write_cb cannot be overflowed by a malicious DoH server because libcurl calls the write callback with size=1 and nmemb limited to the internal receive buffer size (typically 16 KB). The server controls response data, not these parameters. Additionally, the dynamic buffer for DoH responses enforces a 3000-byte limit (toobig=3000) that rejects oversized writes with CURLE_TOO_LARGE before any allocation. The PoC uses nmemb=SIZE_MAX, which a server cannot induce, and even that would be caught by the toobig check. Per project policy, server-triggered crashes without further impact are not treated as security issues. We consider this report invalid.
Inspect all claims and source code 5 claims · 1 code excerpts
Report claims
The multiplication of size and nmemb can overflow, causing a smaller-than-expected buffer allocation.
Read the reasoning
The integer multiplication can theoretically overflow, but the write callback is invoked by libcurl with size=1 and nmemb limited to the internal receive buffer size. A malicious DoH server controls response content, not the callback parameters. Additionally, the dynbuf enforces a 3000-byte limit via toobig, so oversized realsize is rejected with CURLE_TOO_LARGE before any allocation.
The overflow occurs in the doh_probe_write_cb function in lib/doh.c.
Read the reasoning
The location claim is correct: the function exists at the cited file and lines.
A malicious DoH server sends a crafted size that causes integer overflow when multiplied by nmemb.
Read the reasoning
The trigger claims a malicious DoH server can send a crafted size that causes overflow when multiplied by nmemb. In reality, libcurl—not the server—controls size and nmemb. The server only controls response data; libcurl reads it in bounded chunks and calls the callback with size=1, nmemb=chunk_size. Overflow via server action is not possible.
The overflow leads to a heap overflow when the caller accesses the buffer, potentially causing a crash or arbitrary code execution.
Read the reasoning
The dynbuf's toobig check prevents allocation of a too-small buffer. Even if a crash occurred, the project policy classifies server-triggered crashes as not security issues absent special circumstances.
The PoC uses nmemb = (size_t)-1 to trigger integer overflow, causing a crash in doh_probe_write_cb.
Read the reasoning
The PoC does not demonstrate a real overflow (size=1 * nmemb=SIZE_MAX = SIZE_MAX, no wrap-around). The dynbuf's toobig limit would catch the excessive length and return CURLE_TOO_LARGE, so the PoC as written would not crash. The crash claim is not supported by the provided code.
Read the original report (excerpt)
Source code
| 176 | static size_t |
| C2: The function doh_probe_write_cb is defined at lib/doh.c:176-189. | |
| 177 | doh_probe_write_cb(char *contents, size_t size, size_t nmemb, void *userp) |
| 178 | { |
| 179 | size_t realsize = size * nmemb; |
| C1: The multiplication size * nmemb is performed, but libcurl calls write callbacks with size=1 and nmemb=bytes_read (bounded by receive buffer size, typically 16KB). A malicious server cannot cause size and nmemb to be large enough to overflow size_t. | |
| C3: The parameters size and nmemb are provided by libcurl's transfer logic (Curl_client_write), which calls the write callback as fwrite_func(buffer, 1, nread, ...). nread is the number of bytes actually read from the socket, capped by the receive buffer size (e.g., 16KB). A server cannot craft these values. | |
| 180 | struct Curl_easy *data = userp; |
| 181 | struct doh_request *doh_req = Curl_meta_get(data, CURL_EZM_DOH_PROBE); |
| 182 | if(!doh_req) |
| 183 | return CURL_WRITEFUNC_ERROR; |
| 184 | |
| 185 | if(curlx_dyn_addn(&doh_req->resp_body, contents, realsize)) |
| 186 | return 0; |
| 187 | |
| 188 | return realsize; |
| 189 | } |