✓ProveIt
Examples / Report #2298307 Saved analysis

Buffer Overflow Vulnerability in WebSocket Handling

curl · 2023-12-2812.9s analysis · $0.009 in model calls

What the report claims

Buffer overflow in WebSocket handling due to unsafe use of strcpy without bounds checking.

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.

Why this finding?
  • The code has an explicit bounds check (lines 579-580) before the strcpy that returns CURLE_FAILED_INIT if the base64-encoded nonce would not fit in keyval.
  • The WebSocket nonce is generated internally by curl via Curl_rand (16 random bytes), not supplied by an attacker. The attacker cannot control its length.
  • The base64 encoding of 16 bytes produces ~22 characters, well within typical buffer sizes, and the bounds check handles any edge cases.
How this analysis ran 5 claims · 9 citations verified

Checked against curl permalink e251e858b941 (e251e858b941). 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
partially grounded
no model · 2 references checked out, 1 did not
2 · Claims
NVIDIA-Nemotron-3-Nano-30B-A3B
5 claims · 1301 tokens · $0.0001
3 · Evidence
1 code snippets
real curl source at e251e858b941
4 · Judgment
Nemotron-3-Ultra-550b-a55b
5237 tokens · 5.7s · $0.0084
5 · Receipts
9 of 9 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 code at lib/ws.c lines 579-580 shows an explicit bounds check before the strcpy at line 581: if(randlen >= sizeof(keyval)) return CURLE_FAILED_INIT;. Additionally, the WebSocket nonce is generated internally by curl (Curl_rand at line 572), not provided by an attacker, so an attacker cannot supply an oversized value. This is not a buffer overflow vulnerability.

Inspect all claims and source code 5 claims · 1 code excerpts

Report claims

C1flaw contradicted

The report claims that strcpy is used without proper bounds checking, leading to a buffer overflow.

Read the reasoning

The code at lines 579-580 shows an explicit bounds check before the strcpy at line 581. The strcpy only executes if randlen < sizeof(keyval), so there is proper bounds checking.

C2location supported

The vulnerable code is located in lib/ws.c at line 581.

Read the reasoning

The report correctly identifies the location of the strcpy call at line 581 of lib/ws.c.

C3trigger contradicted

A base64-encoded nonce value that exceeds the buffer size can trigger the overflow.

Read the reasoning

The nonce is generated by curl internally via Curl_rand (16 random bytes) and then base64-encoded. An attacker cannot provide or control this nonce value; it is not attacker-controlled input.

C4impact contradicted

An attacker could execute arbitrary code by overwriting adjacent memory.

Read the reasoning

Since the bounds check at lines 579-580 prevents the strcpy when the encoded string would not fit, arbitrary code execution via buffer overflow on this path is not possible.

C5reproduction contradicted

The steps to reproduce involve triggering WebSocket functionality with a crafted request containing an oversized base64-encoded nonce.

Read the reasoning

The reproduction steps describe providing a crafted base64-encoded nonce, but the code shows the nonce is generated internally by curl. An attacker cannot supply an oversized nonce to trigger this code path.

Deterministic checks that failed

  • symbol strncpy() is not called in lib/ws.c at e251e858b941
Read the original report

Full report on HackerOne ↗

## Summary: Hello security team, Hope you are doing well :) I would like to report a potential security vulnerability in the WebSocket handling code of the curl library. The issue is related to the usage of the `strcpy` function, which can lead to a buffer overflow if the length of the input is not properly checked. The vulnerable code snippet is located at [this link](https://github.com/curl/curl/blob/e251e858b941e29bb95a6c0d26bb45981a872585/lib/ws.c#L581). ## Steps To Reproduce: 1. Trigger the WebSocket functionality with a crafted request. 2. Provide a base64-encoded nonce value that exceeds the buffer size. 3. Observe that the `strcpy` function is used without proper bounds checking. ## Fix: To address this issue, it is recommended to replace the `strcpy` function with the safer alternative `strncpy` and explicitly specify the maximum length to copy. Here's an example fix: ```c strncpy(keyval, randstr, sizeof(keyval) - 1); keyval[sizeof(keyval) - 1] = '\0'; // Null-terminate the string ``` This modification ensures that only a specified number of characters (up to the buffer size minus 1) are copied, preventing buffer overflow. ## Reference: https://cwe.mitre.org/data/definitions/122.html ## Impact This vulnerability may allow an attacker to execute arbitrary code, potentially leading to a compromise of the application or system. An attacker could exploit this weakness by providing a specially crafted WebSocket request, causing a buffer overflow and overwriting adjacent memory.

Source code

lib/ws.clines 556–606 · lines 581-581 cited by the report
556 |Sec-WebSocket-Version|. The value of this header field MUST be
557 13. */
558 "Sec-WebSocket-Version:", "13",
559 },
560 {
561 /* The request MUST include a header field with the name
562 |Sec-WebSocket-Key|. The value of this header field MUST be a nonce
563 consisting of a randomly selected 16-byte value that has been
564 base64-encoded (see Section 4 of [RFC4648]). The nonce MUST be
565 selected randomly for each connection. */
566 "Sec-WebSocket-Key:", NULL,
567 }
568 };
569 heads[3].val = &keyval[0];
570
571 /* 16 bytes random */
572 result = Curl_rand(data, (unsigned char *)rand, sizeof(rand));
C3: Curl_rand generates the nonce internally: Curl_rand(data, (unsigned char *)rand, sizeof(rand));
C5: Nonce is generated by Curl_rand, not provided by attacker
573 if(result)
574 return result;
575 result = Curl_base64_encode((char *)rand, sizeof(rand), &randstr, &randlen);
C3: Curl_base64_encode encodes the internally generated random bytes
C5: Base64 encoding is of internally generated random bytes
576 if(result)
577 return result;
578 DEBUGASSERT(randlen < sizeof(keyval));
579 if(randlen >= sizeof(keyval))
C1: Explicit bounds check: if(randlen >= sizeof(keyval)) return CURLE_FAILED_INIT;
C4: Bounds check prevents buffer overflow
580 return CURLE_FAILED_INIT;
C1: Bounds check prevents strcpy when input would overflow
C4: Function returns error if bounds would be exceeded
581 strcpy(keyval, randstr);
C2: strcpy(keyval, randstr); at line 581
582 free(randstr);
583 for(i = 0; !result && (i < sizeof(heads)/sizeof(heads[0])); i++) {
584 if(!Curl_checkheaders(data, STRCONST(heads[i].name))) {
585#ifdef USE_HYPER
586 char field[128];
587 msnprintf(field, sizeof(field), "%s %s", heads[i].name,
588 heads[i].val);
589 result = Curl_hyper_header(data, req, field);
590#else
591 (void)data;
592 result = Curl_dyn_addf(req, "%s %s\r\n", heads[i].name,
593 heads[i].val);
594#endif
595 }
596 }
597 k->upgr101 = UPGR101_WS;
598 return result;
599}
600
601/*
602 * 'nread' is number of bytes of websocket data already in the buffer at
603 * 'mem'.
604 */
605CURLcode Curl_ws_accept(struct Curl_easy *data,
606 const char *mem, size_t nread)