✓ProveIt
Examples / Report #3346118 Saved analysis

Timing Attack Vulnerability in curl Digest Authentication via Non-Constant-Time String Comparison

curl · 2025-09-1816.4s analysis · $0.011 in model calls

What the report claims

A timing attack vulnerability exists in curl's Digest Authentication implementation due to non-constant-time string comparison (strcmp()) when comparing authentication algorithms in digest.c line 360, allowing attackers to determine supported authentication algorithms through response time analysis.

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

Needs human review

The available evidence does not settle the report. A maintainer should investigate.

Judgment withdrawn. The answer failed the evidence check.
See the withdrawn model reasoning

The following reasoning failed the citation check and does not support the final finding.

  • The compared 'algorithm' string is provided by the server in the WWW-Authenticate HTTP header, which is transmitted in plaintext. Any party able to measure curl's processing time can also read the header directly.
  • No secret value is being compared; the check merely verifies the server offers the single algorithm curl supports (md5-sess). A timing attack reveals no information not already public.
  • The project policy does not list timing attacks on public values as security issues, and this case does not cross a security boundary.
How this analysis ran 5 claims · 5 citations verified

Evidence check: judge said likely_invalid without a code citation contradicting a central claim

Checked against curl master on 2025-09-18 (ce354d0f4d25). Dev 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 · 3 references checked out, 0 did not
2 · Claims
NVIDIA-Nemotron-3-Nano-30B-A3B
5 claims · 1710 tokens · $0.0002
3 · Evidence
2 code snippets
real curl source at ce354d0f4d25 · 1 docs via Tavily
4 · Judgment
Nemotron-3-Ultra-550b-a55b
7179 tokens · 10.9s · $0.0111
5 · Receipts
5 of 5 citations verified
every citation must point at code the judge was shown
Inspect the withdrawn draft reply

This draft belongs to the withdrawn judgment. It may contain unsupported claims.

Thank you for the report. The strcmp() at digest.c:360 compares the 'algorithm' value parsed from the server's WWW-Authenticate header, which is sent in cleartext. Since the algorithm is public, a timing difference reveals no secret information an observer cannot already read from the HTTP response. This does not cross a security boundary in curl's threat model.

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

This model judgment was withdrawn. The claim assessments below are preserved for inspection and may be wrong.

Report claims

C1flaw supported

non-constant-time string comparison (strcmp()) when comparing authentication algorithms

Read the reasoning

The code at line 360 indeed uses strcmp() for string comparison, which is not constant-time.

C2location supported

digest.c line 360

Read the reasoning

The report correctly identifies the location.

C3trigger supported

response time analysis of algorithm comparisons

Read the reasoning

strcmp() does have data-dependent timing, so response time analysis could theoretically detect differences.

C4impact contradicted

determine supported authentication algorithms on the server

Read the reasoning

The 'algorithm' string comes from the server's WWW-Authenticate header, which is sent in plaintext. An attacker who can observe timing can also simply read the header. No secret is being protected.

C5reproduction not verifiable

PoC script showing timing differences between MD5, MD5-sess, and SHA-1 algorithms

Read the reasoning

PoC script not provided in materials; cannot verify its methodology or results.

Read the original report (excerpt)

Full report on HackerOne ↗

## Summary: A timing attack vulnerability exists in curl's Digest Authentication implementation due to the use of non-constant-time string comparison (strcmp()) when comparing authentication algorithms in digest.c line 360. This allows attackers to determine the supported authentication algorithm through response time analysis. No AI was used to discover this vulnerability or generate this report. ## Affected version * curl version 7.88.1 (x86_64-pc-linux-gnu) * libcurl/7.88.1 OpenSSL/3.0.8 zlib/1.2.13 libidn2/2.3.4 libpsl/0.21.2 (+libidn2/2.3.4) libssh2/1.10.0 nghttp2/1.52.0 * Platform: Linux Ubuntu 22.04.3 LTS ## Steps To Reproduce: 1. Set up a test server with Digest Authentication enabled: bash ``` # Using a simple Python HTTP server with digest auth python3 -m http.server 8080 --digest ``` 2. Run the timing attack PoC against the local server: {F4799894} bash ``` python3 poc_timing_attack.py http://localhost:8080/protected ``` 3. Observe the timing differences between algorithm comparisons: text ``` Testing algorithm: MD5 - 963236.5 ns Testing algorithm: MD5-sess - 826390.0 ns Testing algorithm: SHA-1 - 814495.0 ns ``` 4. The PoC will identify the algorithm with significantly different response times: text ``` VULNERABILITY CONFIRMED: Timing attack possible The server likely uses algorithm: MD5 Response time: 963236.50 ns Deviation: +25.9% from average ``` ## Supporting Material/References: * PoC script output showing timing differences *Vulnerable code location in digest.c line 360 *curl documentation on Digest Authentication : https://everything.curl.dev/libcurl-http/auth.html ## Impact ## Summary: An attacker can exploit this vulnerability to: 1. Determine supported authentication algorithms on the server 2. Facilitate targeted attacks by identifying weaker algorithms (e.g., MD5 vs SHA-256) 3. Gain reconnaissance information about server configuration 4. Potentially bypass authentication if combined with other vulnerabilities The vulnerability violates the principle of constant-time comparison for security-sensitive operations and could lead to authentication mechanism fingerprinting. ##Additional Information: * CVSS Score: 5.3 (Medium) - CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N * Fix Recommendation: Replace strcmp() …

Source code

lib/vauth/digest.clines 335–385 · lines 360-360 cited by the report
335 char HA2_hex[2 * MD5_DIGEST_LEN + 1];
336 char resp_hash_hex[2 * MD5_DIGEST_LEN + 1];
337 char nonce[64];
338 char realm[128];
339 char algorithm[64];
340 char qop_options[64];
341 int qop_values;
342 char cnonce[33];
343 char nonceCount[] = "00000001";
344 char method[] = "AUTHENTICATE";
345 char qop[] = DIGEST_QOP_VALUE_STRING_AUTH;
346 char *spn = NULL;
347
348 /* Decode the challenge message */
349 CURLcode result = auth_decode_digest_md5_message(chlg,
C4: algorithm is parsed from server's challenge message (chlg)
350 nonce, sizeof(nonce),
351 realm, sizeof(realm),
352 algorithm,
C4: algorithm buffer filled by auth_decode_digest_md5_message from server response
353 sizeof(algorithm),
354 qop_options,
355 sizeof(qop_options));
356 if(result)
357 return result;
358
359 /* We only support md5 sessions */
360 if(strcmp(algorithm, "md5-sess") != 0)
C1: Uses strcmp(algorithm, "md5-sess") for comparison
C2: Location of the strcmp call
C3: strcmp returns early on mismatch, creating timing differences
361 return CURLE_BAD_CONTENT_ENCODING;
362
363 /* Get the qop-values from the qop-options */
364 result = auth_digest_get_qop_values(qop_options, &qop_values);
365 if(result)
366 return result;
367
368 /* We only support auth quality-of-protection */
369 if(!(qop_values & DIGEST_QOP_VALUE_AUTH))
370 return CURLE_BAD_CONTENT_ENCODING;
371
372 /* Generate 32 random hex chars, 32 bytes + 1 null-termination */
373 result = Curl_rand_hex(data, (unsigned char *)cnonce, sizeof(cnonce));
374 if(result)
375 return result;
376
377 /* So far so good, now calculate A1 and H(A1) according to RFC 2831 */
378 ctxt = Curl_MD5_init(&Curl_DIGEST_MD5);
379 if(!ctxt)
380 return CURLE_OUT_OF_MEMORY;
381
382 Curl_MD5_update(ctxt, (const unsigned char *) userp,
383 curlx_uztoui(strlen(userp)));
384 Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
385 Curl_MD5_update(ctxt, (const unsigned char *) realm,
lib/strcase.clines 129–145 · definition of Curl_timestrcmp
129int Curl_timestrcmp(const char *a, const char *b)
130{
131 int match = 0;
132 int i = 0;
133
134 if(a && b) {
135 while(1) {
136 match |= a[i]^b[i];
137 if(!a[i] || !b[i])
138 break;
139 i++;
140 }
141 }
142 else
143 return a || b;
144 return match;
145}