✓ProveIt
Examples / Report #3744543 Saved analysis

CVE-2026-8927: env-set cross-proxy Digest auth state leak

curl · 2026-05-1815.8s analysis · $0.015 in model calls

What the report claims

Stale Digest proxy authentication state from a previous proxy selected via environment variables is incorrectly sent to a new proxy when reusing a libcurl easy handle.

Compare with curl's recorded outcome

Known vulnerability

A real vulnerability: CVE-2026-8927 env-set cross-proxy Digest auth state leak

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.

Why this finding?
  • The provided curl source only shows curl_easy_reset, which explicitly clears proxy auth state. The critical code — proxy resolution from environment variables (http_proxy/ALL_PROXY) and the perform-time logic that should detect a proxy change and clear stale Digest state — is not included in the source snippets.
  • Deterministic checks confirm the relevant symbols exist but do not show their usage in the proxy resolution or auth state management paths.
  • The report describes a plausible variant of a known CVE (CVE-2026-7168) where the explicit CURLOPT_PROXY path was fixed but the environment-variable path may have been missed. This pattern is credible but cannot be confirmed without the missing code.
  • If the environment-variable proxy resolution path lacks the cleanup that the CURLOPT_PROXY path has, this would be a valid security issue (cross-proxy credential leak). If the cleanup is shared, the report is invalid.
What still needs checking
  • The function that resolves the effective proxy from environment variables (likely in lib/url.c or lib/easy.c) and the code in curl_easy_perform or the HTTP proxy connect logic that manages proxy auth state across transfers on a reused handle.
How this analysis ran 5 claims · 1 citations verified

Checked against curl master on 2026-05-18 (240408a72542). 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 · 5 references checked out, 0 did not
2 · Claims
NVIDIA-Nemotron-3-Nano-30B-A3B
5 claims · 4396 tokens · $0.0004
3 · Evidence
1 code snippets
real curl source at 240408a72542 · 2 docs via Tavily
4 · Judgment
Nemotron-3-Ultra-550b-a55b
10414 tokens · 10.6s · $0.0145
5 · Receipts
1 of 5 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 detailed report and PoC. The issue you describe — a missing proxy-auth cleanup when the effective proxy changes via environment variables — is a plausible variant of CVE-2026-7168. However, the provided source snippets only show curl_easy_reset (an explicit reset), not the proxy resolution logic or the perform-time state management that handles implicit proxy changes. To evaluate this, we need to see the code that resolves proxies from http_proxy/ALL_PROXY and the path in curl_easy_perform (or the HTTP proxy connect logic) that should clear data->state.proxydigest and data->state.authproxy when the effective proxy changes between transfers on a reused handle. Could you point to the specific functions/files where this resolution and cleanup should occur?

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

Report claims

C1flaw not verifiable

When the effective proxy changes through environment variables such as http_proxy or ALL_PROXY, the previous proxy Digest/auth state is not cleared before the second transfer on a reused easy handle.

Read the reasoning

The central claim is that changing the effective proxy via environment variables does not clear proxy Digest/auth state. The provided source snippet only shows curl_easy_reset (an explicit reset API), not the proxy resolution logic or the perform-time state management that would handle implicit proxy changes from environment variables. Without the code that resolves proxies from environment variables and manages auth state across transfers, the claim cannot be verified or contradicted from the provided material.

C2location not verifiable

The issue occurs in the proxy authentication state management of libcurl's easy handle when the proxy is resolved from environment variables.

Read the reasoning

The claim identifies the general area (proxy authentication state management) but the specific code location where environment-variable proxy resolution fails to clear state is not shown in the provided source. The deterministic checks only confirm the symbols exist, not the bug location.

deterministic check
C3trigger not verifiable

Changing the environment variable from proxyA to proxyB while reusing the same easy handle causes the stale Proxy-Authorization header to be sent to the new proxy.

Read the reasoning

The trigger description is plausible but the code path that processes environment variable changes between transfers on a reused handle is not provided. Cannot confirm whether the stale header is actually sent.

deterministic check
C4impact not verifiable

A malicious second proxy can receive a Proxy-Authorization: Digest header generated from the previous proxy's Digest challenge state, enabling replay attacks.

Read the reasoning

Impact claim depends on C1 being true. Since C1 is not verifiable from provided code, impact cannot be assessed.

report:0
C5reproduction not verifiable

The PoC starts two local proxy servers, first uses http_proxy to authenticate with proxyA, then changes http_proxy to point to proxyB and reuses the same easy handle, causing proxyB to receive a stale Proxy-Authorization header containing realm and nonce from proxyA.

Read the reasoning

Reproduction steps describe a test scenario. The actual curl code path that would exhibit the behavior is not in the provided source.

report:0
Read the original report (excerpt)

Full report on HackerOne ↗

## AI-assisted preparation note I used AI assistance to help structure and format this report, but the technical findings, PoC, and verification results are based on local testing against curl/libcurl 8.20.0. ## Summary I found a possible incomplete-fix variant of CVE-2026-7168 in libcurl 8.20.0. The original issue involved stale Digest proxy authentication state being sent from `proxyA` to `proxyB` when the same libcurl easy handle was reused after changing proxies. In curl 8.20.0, the explicit `CURLOPT_PROXY` path appears to be fixed: changing the proxy via `CURLOPT_PROXY` clears the old proxy Digest/auth state correctly. However, I found that the same cleanup does not appear to happen when the effective proxy changes through environment variables such as `http_proxy` or `ALL_PROXY`. As a result, when the same easy handle is reused: 1. The first transfer uses `proxyA` from `http_proxy` and authenticates with HTTP Digest proxy authentication. 2. The environment variable is changed so the next transfer uses `proxyB`. 3. The same easy handle performs the second transfer. 4. `proxyB` receives a `Proxy-Authorization: Digest` header using stale Digest state from `proxyA`. This was reproduced against official curl/libcurl 8.20.0. ## Affected version Tested against official curl/libcurl 8.20.0. The PoC confirms: ```text LIBCURL_RUNTIME=8.20.0 LIBCURL_HEADERS=8.20.0 ``` ## Impact A malicious second proxy can receive a `Proxy-Authorization: Digest` header generated from the previous proxy's Digest challenge state. In my replay test, the header captured by `proxyB` was valid for `proxyA` and could be replayed successfully. This is the same security class as CVE-2026-7168: proxy authentication state intended for one proxy crosses a proxy boundary and is exposed to another proxy. This can allow a malicious proxy to capture and replay Digest proxy authentication material intended for another proxy. ## Technical details The explicit proxy-change path appears to be fixed in 8.20.0. When an application changes the proxy using `CURLOPT_PROXY`, the previous proxy Digest/auth state is cleared. My control test confirmed: ```text CURLOPT_PROXY proxyA -> CURLOPT_PROXY proxyB Result: no stale Proxy-Authorization header sent to proxyB ``` The environment-derived proxy path behaves differently. When the proxy is selected from `http_proxy` or `ALL_PROXY`, chang …

Source code

lib/easy.clines 1084–1118 · definition of curl_easy_reset
1084void curl_easy_reset(CURL *curl)
C1: Only curl_easy_reset is shown, which explicitly clears authproxy and calls Curl_http_auth_cleanup_digest. The proxy resolution logic for environment variables (http_proxy/ALL_PROXY) and the code path that should clear proxy auth state when the effective proxy changes during curl_easy_perform are not provided.
1085{
1086 struct Curl_easy *data = curl;
1087 if(!GOOD_EASY_HANDLE(data))
1088 return;
1089
1090 Curl_req_hard_reset(&data->req, data);
1091 Curl_hash_clean(&data->meta_hash);
1092
1093 /* clear all meta data */
1094 Curl_meta_reset(data);
1095 /* zero out UserDefined data: */
1096 Curl_freeset(data);
1097 memset(&data->set, 0, sizeof(struct UserDefined));
1098 Curl_init_userdefined(data);
1099
1100 /* zero out Progress data: */
1101 memset(&data->progress, 0, sizeof(struct Progress));
1102
1103 /* zero out PureInfo data: */
1104 Curl_initinfo(data);
1105
1106 data->progress.hide = TRUE;
1107 data->state.current_speed = -1; /* init to negative == impossible */
1108 data->state.recent_conn_id = -1; /* clear remembered connection id */
1109
1110 /* zero out authentication data: */
1111 memset(&data->state.authhost, 0, sizeof(struct auth));
1112 memset(&data->state.authproxy, 0, sizeof(struct auth));
1113
1114#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_DIGEST_AUTH)
1115 Curl_http_auth_cleanup_digest(data);
1116#endif
1117 data->master_mid = UINT32_MAX;
1118}