("possible") UAF
What the report claims
Potential Use-After-Free vulnerability in cf_h2_proxy_ctx_free function of libcurl
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
The code provides evidence against the report's central claim. Review the cited lines before deciding.
curl policy: NULL dereferences and crashesWhy this finding?
- The report misidentifies the free function (cf_h2_proxy_ctx_free) as the site of a use-after-free. The function correctly frees memory; a UAF would be in a caller that uses the pointer afterward, but no such caller is shown in curl's code.
- The reproduction example is the reporter's own simulation, not actual curl code. The provided curl source shows no call to cf_h2_proxy_ctx_free followed by use of the freed pointer.
- The project policy lists 'NULL dereferences and crashes' as not security issues when a malicious server can only trigger a crash; this report does not even demonstrate a crash in curl.
What still needs checking
- A concrete code path in curl where cf_h2_proxy_ctx_free is called and the returned/freed pointer is subsequently accessed.
How this analysis ran 5 claims · 5 citations verified
Checked against curl master on 2025-02-07 (3754115750db). Dev evaluation split. Citation verification checks that a referenced line was in the evidence; it does not prove the model interpreted it correctly.
Review a draft reply to the reporter
Edit and verify before sending.
Thank you for the report. The function cf_h2_proxy_ctx_free (lib/cf-h2-proxy.c:208-214) only clears and frees the context — it does not access the pointer after freeing it. A use-after-free would need to be in a caller that uses the pointer after calling this function, but your example code is a standalone simulation, not part of curl. Could you point to a specific location in curl's source where a freed cf_h2_proxy_ctx is accessed?
Inspect all claims and source code 5 claims · 2 code excerpts
Report claims
Potential Use-After-Free (UAF) vulnerability in the cf_h2_proxy_ctx_free function of libcurl
Read the reasoning
The claim states the UAF vulnerability is *in* cf_h2_proxy_ctx_free. The provided code shows this function only clears and frees the context; it does not access the pointer after freeing it. A use-after-free would have to occur in a *caller* that uses the pointer after calling this function, but no such caller is identified in the report or the provided source.
The vulnerability occurs in the cf_h2_proxy_ctx_free function of libcurl
Read the reasoning
Same as C1: the function shown is the free function. The report's example code demonstrates a UAF in the *caller* (trigger_bug), but that caller is the reporter's own test program, not curl code.
Accessing the cf_h2_proxy_ctx object after it has been freed
Read the reasoning
The report does not point to any actual curl code path where a freed cf_h2_proxy_ctx is accessed. The provided source only contains the free function definition and main(); no callers of cf_h2_proxy_ctx_free are visible.
Potential crashes, memory corruption, or security vulnerabilities if exploited
Read the reasoning
Generic impact claims; no concrete exploit path in curl is demonstrated.
The example code demonstrates freeing a context object (cf_h2_proxy_ctx) and then accessing it
Read the reasoning
The reproduction code is the reporter's own test program (main() with malloc/free/trigger_bug). It does not exist in curl. The actual curl main() in src/tool_main.c does not allocate or free cf_h2_proxy_ctx.
Read the original report (excerpt)
Source code
| 208 | static void cf_h2_proxy_ctx_free(struct cf_h2_proxy_ctx *ctx) |
| C1: cf_h2_proxy_ctx_free correctly frees the context after clearing it; the function itself does not access freed memory | |
| C2: The vulnerability location is misidentified; cf_h2_proxy_ctx_free is the free function, not a site of use-after-free | |
| C3: No caller of cf_h2_proxy_ctx_free is shown in the provided source; cannot verify whether any curl code accesses the freed object | |
| C5: The example code in the report is a standalone simulation written by the reporter, not code from curl's codebase | |
| 209 | { |
| 210 | if(ctx) { |
| C1: The function only calls cf_h2_proxy_ctx_clear(ctx) then free(ctx) — no use-after-free in this function | |
| 211 | cf_h2_proxy_ctx_clear(ctx); |
| 212 | free(ctx); |
| 213 | } |
| 214 | } |
| 236 | int main(int argc, char *argv[]) |
| 237 | #endif |
| 238 | { |
| 239 | CURLcode result = CURLE_OK; |
| 240 | struct GlobalConfig global; |
| 241 | memset(&global, 0, sizeof(global)); |
| 242 | |
| 243 | tool_init_stderr(); |
| 244 | |
| 245 | #ifdef _WIN32 |
| 246 | /* Undocumented diagnostic option to list the full paths of all loaded |
| 247 | modules. This is purposely pre-init. */ |
| 248 | if(argc == 2 && !_tcscmp(argv[1], _T("--dump-module-paths"))) { |
| 249 | struct curl_slist *item, *head = GetLoadedModulePaths(); |
| 250 | for(item = head; item; item = item->next) |
| 251 | printf("%s\n", item->data); |
| 252 | curl_slist_free_all(head); |
| 253 | return head ? 0 : 1; |
| 254 | } |
| 255 | /* win32_init must be called before other init routines. */ |
| 256 | result = win32_init(); |
| 257 | if(result) { |
| 258 | errorf(&global, "(%d) Windows-specific init failed", result); |
| 259 | return (int)result; |
| 260 | } |
| 261 | #endif |
| 262 | |
| 263 | if(main_checkfds()) { |
| 264 | errorf(&global, "out of file descriptors"); |
| 265 | return CURLE_FAILED_INIT; |
| 266 | } |
| 267 | |
| 268 | #if defined(HAVE_SIGNAL) && defined(SIGPIPE) |
| 269 | (void)signal(SIGPIPE, SIG_IGN); |
| 270 | #endif |
| 271 | |
| 272 | /* Initialize memory tracking */ |
| 273 | memory_tracking_init(); |
| 274 | |
| 275 | /* Initialize the curl library - do not call any libcurl functions before |
| 276 | this point */ |
| 277 | result = main_init(&global); |
| 278 | if(!result) { |
| 279 | /* Start our curl operation */ |
| 280 | result = operate(&global, argc, argv); |
| 281 | |
| 282 | /* Perform the main cleanup */ |
| 283 | main_free(&global); |
| 284 | } |
| 285 | |
| 286 | #ifdef _WIN32 |
| 287 | /* Flush buffers of all streams opened in write or update mode */ |
| 288 | fflush(NULL); |
| 289 | #endif |
| 290 | |
| 291 | #ifdef __VMS |
| 292 | vms_special_exit(result, vms_show); |
| 293 | #else |
| 294 | return (int)result; |
| 295 | #endif |
| 296 | } |