✓ProveIt
Examples / Report #3399774 Saved analysis

Integer Overflow to Heap Overflow in DoH Response Handling

curl · 2025-10-2520.0s analysis · $0.018 in model calls

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

Code contradicts the claim

The code provides evidence against the report's central claim. Review the cited lines before deciding.

curl policy: NULL dereferences and crashes
Why 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.

1 · Grounding
grounded
no model · 7 references checked out, 0 did not
2 · Claims
NVIDIA-Nemotron-3-Nano-30B-A3B
5 claims · 2371 tokens · $0.0002
3 · Evidence
1 code snippets
real curl source at c59bf9018633
4 · Judgment
Nemotron-3-Ultra-550b-a55b
9007 tokens · 14.9s · $0.0179
5 · Receipts
3 of 7 citations verified
every citation must point at code the judge was shown
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

C1flaw contradicted

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.

lib/doh.c:179 lib/curlx/dynbuf.c:12
C2location supported

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.

C3trigger contradicted

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.

C4impact contradicted

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.

lib/curlx/dynbuf.c:12 project_policy:108
C5reproduction contradicted

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.

lib/curlx/dynbuf.c:12
Read the original report (excerpt)

Full report on HackerOne ↗

## Summary: An integer overflow vulnerability exists in the `doh_probe_write_cb` function in `lib/doh.c`. This function is used as a write callback for DNS-over-HTTPS (DoH) responses. When a malicious DoH server sends a response with a crafted size, the multiplication of `size` and `nmemb` can overflow. This leads to the allocation of a smaller-than-expected buffer on the heap, but the function returns the wrapped-around, incorrect size. This discrepancy can lead to a heap overflow when the caller subsequently tries to access the buffer, resulting in a crash or potential arbitrary code execution. ## Affected version This vulnerability was found on the current master branch of the curl repository. It can be reproduced on a standard Linux build. ## Steps To Reproduce: 1. Save the following Proof-of-Concept code as `poc.c` in the root of the curl project directory: ```c #include <stdio.h> #include <string.h> #include <stdlib.h> #define CURL_STATICLIB #include <curl/curl.h> // --- From curl/lib/curlx/dynbuf.h --- struct dynbuf { char *bufr; size_t leng; size_t allc; size_t toobig; }; #define DYN_DOH_RESPONSE 3000 // --- From curl/lib/curlx/dynbuf.c --- void curlx_dyn_init(struct dynbuf *s, size_t toobig) { s->bufr = NULL; s->leng = 0; s->allc = 0; s->toobig = toobig; } void curlx_dyn_free(struct dynbuf *s) { free(s->bufr); s->bufr = NULL; s->leng = 0; s->allc = 0; } CURLcode dyn_nappend(struct dynbuf *s, const unsigned char *mem, size_t len) { size_t idx = s->leng; size_t a = s->allc; size_t fit = len + idx + 1; if(len > s->toobig - idx - 1) { // check for overflow before addition return CURLE_TOO_LARGE; } if(!a) { a = fit; } else { while(a < fit) a *= 2; } if(a != s->allc) { void *p = realloc(s->bufr, a); if(!p) { curlx_dyn_free(s); return CURLE_OUT_OF_MEMORY; } s->bufr = p; s->allc = a; } if(len) memcpy(&s->bufr[idx], mem, len); s->leng = idx + len; s->bufr[s->leng] = 0; return CURLE_OK; } CURLcode curlx_dyn_addn(struct dynbuf *s, const void *mem, size_t len) { return dyn_nappend(s, (const un …

Source code

lib/doh.clines 176–189 · definition of doh_probe_write_cb
176static size_t
C2: The function doh_probe_write_cb is defined at lib/doh.c:176-189.
177doh_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}