HexBrain

curl · Report #3682666

Use-after-free in `curl_easy_ssls_export()` during callback re-entrancy

N/Astatus
highseverity
8upvotes
29 Apr 2026disclosed

How it was found

Summary:

curl_easy_ssls_export() iterates the SSL session list and invokes a caller-provided callback for each entry. If that callback calls curl_easy_ssls_import() on the same easy handle, the import path can evict and free the current session node while the export loop still holds it. The subsequent Curl_node_next(n) dereferences freed memory and triggers AddressSanitizer as a heap-use-after-free. I reproduced this on curl GitHub HEAD 54ded66618a2388e88e715c5eb4477d1083582ef. The relevant code path is lib/vtls/vtls_scache.c, primarily Curl_ssl_session_export() around line 1214 with the related eviction path in cf_scache_peer_add_session() around line 781.

Affected version

Reproduced on libcurl built from curl GitHub HEAD 54ded66618a2388e88e715c5eb4477d1083582ef on Linux x86_64. The build used the OpenSSL backend with clang, AddressSanitizer, UndefinedBehaviorSanitizer, and configure options --disable-shared --enable-ssls-export --with-openssl.

Steps To Reproduce:

  1. Build the tested curl source with OpenSSL and --enable-ssls-export, for example:
autoreconf -fi
CC=clang CFLAGS="-fsanitize=address,undefined -fno-omit-frame-pointer -g -O1" \
LDFLAGS="-fsanitize=address,undefined" \
./configure --disable-shared --enable-ssls-export --with-openssl
make -j"$(nproc)"
  1. Compile the attached poc.c against the freshly built static libcurl:
clang -fsanitize=address,undefined -fno-omit-frame-pointer -g -O1 \
  -I./include -I./lib \
  poc.c ./lib/.libs/libcurl.a \
  -lssl -lcrypto -lz -lpthread -ldl \
  -o /tmp/poc_curl_ssls_export_uaf
  1. Run the PoC:
ASAN_OPTIONS="halt_on_error=0:print_stacktrace=1:detect_leaks=0" \
UBSAN_OPTIONS="print_stacktrace=1:halt_on_error=0" \
  /tmp/poc_curl_ssls_export_uaf
  1. The PoC imports TLS session entries for the same peer and then calls curl_easy_ssls_export(). During the export callback it re-enters curl_easy_ssls_import() on the same easy handle, mutating the session list while the export code still holds the current node.

Observed sanitizer output:

ERROR: AddressSanitizer: heap-use-after-free
#0 Curl_node_next /src/curl/lib/llist.c:246
#1 Curl_ssl_session_export /src/curl/lib/vtls/vtls_scache.c:1214

Impact

An application using the SSL session export/import API can trigger a heap use-after-free in libcurl. In the tested build this is a reliable crash. In non-instrumented builds, dereferencing a freed list node may also lead to memory corruption, depending on allocator state and surrounding heap layout.

This report was disclosed publicly on HackerOne and belongs to its author and the program. See the original