✓ProveIt
Examples / Report #3516186 Saved analysis

Cookie Max-Age Integer Overflow Vulnerability

curl · 2026-01-1923.8s analysis · $0.025 in model calls

What the report claims

The cookie parsing code in lib/cookie.c contains an integer overflow vulnerability when processing the Max-Age attribute of HTTP cookies, allowing attacker-controlled Max-Age values to cause incorrect cookie expiration calculations.

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 overflow check `CURL_OFF_T_MAX - now < co->expires` is correct and cannot itself overflow because `now` (Unix timestamp, ~1.7e9) is orders of magnitude smaller than `CURL_OFF_T_MAX` (~9.2e18).
  • The addition `co->expires += now` is executed only in the `else` branch where the check proved no overflow would occur.
  • Parsed Max-Age values are capped at `CURL_OFF_T_MAX` by `curlx_str_number` (line 592, 596-599).
  • After Max-Age processing, `cap_expires(now, co)` is called (line 614), which should enforce the RFC's 400-day cookie-age-limit.
  • No integer overflow or wrap-around occurs in the provided code.
How this analysis ran 6 claims · 8 citations verified

Evidence check: judge quoted an external source that does not say that (https://www.ietf.org/archive/id/draft-ietf-httpbis-rfc6265bis-20.html)

Checked against curl master on 2026-01-19 (9703dabd77b5). 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 · 9 references checked out, 0 did not
2 · Claims
NVIDIA-Nemotron-3-Nano-30B-A3B
6 claims · 2820 tokens · $0.0003
3 · Evidence
3 code snippets
real curl source at 9703dabd77b5 · 6 docs via Tavily
4 · Judgment
Nemotron-3-Ultra-550b-a55b
16023 tokens · 19.5s · $0.0247
5 · Receipts
8 of 8 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 detailed report. The code at lib/cookie.c:607-611 does not have the integer overflow you describe. The check `CURL_OFF_T_MAX - now < co->expires` is a standard safe addition guard: `now` comes from `time(NULL)` (~1.7e9) while `CURL_OFF_T_MAX` is ~9.2e18, so the subtraction cannot overflow. The addition only runs when the check proves it is safe. Parsed Max-Age values are capped at `CURL_OFF_T_MAX` by `curlx_str_number`, and `cap_expires` is called afterward to enforce the RFC's 400-day limit. No wrap-around or indefinite persistence occurs. If you have a concrete input that produces a wrong expiry with the current code, please share it.

Inspect all claims and source code 6 claims · 3 code excerpts

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

Report claims

C1flaw contradicted

The overflow check CURL_OFF_T_MAX - now < co->expires can itself overflow when now is large, leading to incorrect bounds checking before adding now to co->expires

Read the reasoning

The report claims the subtraction `CURL_OFF_T_MAX - now` can overflow when `now` is large. In reality, `now` is the current Unix timestamp (seconds since 1970), which is at most a few billion even in the far future, while CURL_OFF_T_MAX is ~9.2 quintillion. The subtraction is completely safe.

C2flaw contradicted

The addition co->expires += now is performed without verifying that the result does not overflow, causing potential wrap‑around

Read the reasoning

The addition is guarded by the preceding overflow check. The code follows the standard safe pattern: check `MAX - b < a` before computing `a + b`.

C3flaw contradicted

The code uses CURL_OFF_T_MAX - now < co->expires as a guard, but this subtraction can underflow or overflow when now is close to CURL_OFF_T_MAX

Read the reasoning

The claim repeats C1's misunderstanding. `now` is a Unix timestamp, not an attacker-controlled value, and is always tiny compared to CURL_OFF_T_MAX.

C4flaw contradicted

An attacker can supply a Max-Age value that is extremely large (near CURL_OFF_T_MAX) to trigger the overflow conditions

Read the reasoning

An attacker can send a large Max-Age, but `curlx_str_number` caps the parsed value at CURL_OFF_T_MAX, and the overflow check at line 607 correctly handles that capped value. No overflow condition is triggered.

C5flaw contradicted

When the overflow occurs, co->expires may be set to CURL_OFF_T_MAX or wrap around, resulting in cookies that persist indefinitely or expire immediately

Read the reasoning

On overflow the code sets `co->expires` to CURL_OFF_T_MAX (saturating), not wrapping. Then `cap_expires` applies the RFC's 400-day limit. Cookies do not persist indefinitely or expire immediately due to this code path.

C6flaw not verifiable

Multiple crafted Set-Cookie headers with large Max-Age values can fill the cookie jar, leading to denial of service

Read the reasoning

Cookie jar limits exist, but the claimed overflow does not occur (per C1-C5), so this DoS scenario does not follow from the alleged integer overflow. Whether a separate DoS exists via many cookies is not settled by the provided code.

What the report says about other projects

confirmed The RFC 6265bis draft specifies that Max-Age values must be non‑negative and that overflow must be handled safely

“If the expiry-time is more than cookie-age-limit, the user agent MUST set the expiry time to cookie-age-limit in seconds. If the expiry-time is earlier than the earliest date the user agent can represent, the user agent MAY replace the expiry-time with the earliest representable date.” source

Read the original report (excerpt)

Full report on HackerOne ↗

## Summary: The cookie parsing code in `lib/cookie.c` contains an integer overflow vulnerability when processing the `Max-Age` attribute of HTTP cookies. The vulnerable code attempts to add the max-age value to the current timestamp without adequate overflow protection While the code includes an overflow check (`CURL_OFF_T_MAX - now < co->expires`), this check itself can experience integer overflow in edge cases where: 1. The `max-age` value is extremely large (near `CURL_OFF_T_MAX`) 2. The current time (`now`) is large enough that the subtraction `CURL_OFF_T_MAX - now` produces unexpected results 3. The addition `co->expires += now` occurs without proper bounds checking An attacker can exploit this vulnerability by: 1. Controlling a web server or performing a man-in-the-middle attack 2. Sending HTTP responses with `Set-Cookie` headers containing extremely large `Max-Age` values 3. Causing curl/libcurl to incorrectly calculate cookie expiration times 4. Resulting in cookies persisting beyond their intended lifetime or being immediately expired **Vulnerable Code Location:** `lib/cookie.c:607-611` ```c else if(CURL_OFF_T_MAX - now < co->expires) /* would overflow */ co->expires = CURL_OFF_T_MAX; else co->expires += now; ``` ## Affected version **Affected Versions:** curl 7.x - 8.x ## Steps To Reproduce: ### Vulnerable Code Flow 1. **Cookie Header Parsing** (`parse_cookie_header()`) - Parses `Max-Age` attribute from `Set-Cookie` header - Calls `curlx_str_number()` to convert string to integer - Handles overflow cases but with insufficient protection 2. **Overflow Check** (Line 607) ```c if(CURL_OFF_T_MAX - now < co->expires) ``` - This check can itself overflow when `now` is large - Does not account for all edge cases 3. **Time Addition** (Line 611) ```c co->expires += now; ``` - Performs addition without verifying result - Can wrap around on overflow ### Exploitation Scenarios #### Scenario 1: Maximum Max-Age Value ```http HTTP/1.1 200 OK Set-Cookie: session=abc123; Max-Age=9223372036854775807; Path=/ ``` - Max-Age set to `CURL_OFF_T_MAX` (64-bit maximum) - When added to current time, may overflow - Cookie may expire immediately or persist indefinitely #### Scenario 2: Near-Overflow Value ```http HTTP/1.1 200 OK Set-Cookie: tracking=xyz; Max-Age=9223372036854000000; Path=/ ``` - Max-Age chosen to …

Source code

lib/cookie.clines 428–636 · lines 607-611 cited by the report; definition of parse_cookie_header (truncated)
C6: Line 447-449: lines longer than MAX_COOKIE_LINE are discarded. The cookie jar has other limits (MAX_NAME, etc.).
C4: Line 592: `rc = curlx_str_number(&maxage, &co->expires, CURL_OFF_T_MAX);` passes CURL_OFF_T_MAX as the maximum. Lines 596-599: on STRE_OVERFLOW, `co->expires = CURL_OFF_T_MAX`.
C1: The check `CURL_OFF_T_MAX - now < co->expires` uses `now` from `time(NULL)` (line 594, 636). Current Unix time is ~1.7e9; CURL_OFF_T_MAX is 0x7FFFFFFFFFFFFFFF (~9.2e18). The subtraction cannot overflow or underflow because `now` is many orders of magnitude smaller than CURL_OFF_T_MAX.
C2: Line 607 `else if(CURL_OFF_T_MAX - now < co->expires)` is the bounds check. If true (addition would overflow), line 609 sets `co->expires = CURL_OFF_T_MAX`. The addition `co->expires += now` at line 611 only executes in the `else` branch where the check proved no overflow.
C3: Same as C1: `now` is never close to CURL_OFF_T_MAX. The subtraction cannot underflow (now is positive and far smaller than CURL_OFF_T_MAX) and cannot overflow (result fits in curl_off_t).
C4: The subsequent check at line 607 correctly handles any value up to CURL_OFF_T_MAX.
C5: Line 609: `co->expires = CURL_OFF_T_MAX;` on detected overflow — no wrap-around.
C5: Line 614: `cap_expires(now, co);` is called after Max-Age processing, which per RFC 6265bis should cap expiry to 400 days (cookie-age-limit).
lib/curl_setup.hlines 569–569 · definition of CURL_OFF_T_MAX
569# define CURL_OFF_T_MAX 0x7FFFFFFFFFFFFFFF
lib/curlx/strparse.clines 195–198 · definition of curlx_str_number
Show 4 lines (not cited by the judge)
195int curlx_str_number(const char **linep, curl_off_t *nump, curl_off_t max)
196{
197 return str_num_base(linep, nump, max, 10);
198}