
Proof-of-Concept zur Reproduktion von CVE-2026-8932, einer Schwachstelle durch unvollständige mTLS-Konfigurationsübereinstimmung bei der Verbindungswiederverwendung in libcurl, mit einem lokalen Lab-Server und einem C-PoC.
Proof-of-Concept-Reproduktion von CVE-2026-8932, einem Problem bei der unvollständigen Übereinstimmung der mTLS-Konfiguration in der Verbindungswiederverwendung von libcurl.
CVE-2026-8932 betrifft die Logik zur Wiederverwendung von Verbindungen in libcurl, wenn sich die Mutual-TLS-Konfiguration (mTLS) zwischen Anfragen ändert.
Unter anfälligen Bedingungen kann libcurl eine bestehende TLS-Verbindung wiederverwenden, obwohl sich eine mTLS-bezogene Konfigurationsoption geändert hat und die Wiederverwendung dieser Verbindung hätte verhindern sollen.
Dieses PoC demonstriert das Problem, indem das Passwort für den privaten Schlüssel zwischen zwei Anfragen geändert wird, während dasselbe Client-Zertifikat und derselbe private Schlüssel verwendet werden.
Die erste Anfrage verwendet das korrekte Passwort:
correct-password
Die zweite Anfrage verwendet absichtlich ein ungültiges Passwort:
WRONG-PASSWORD
Wenn libcurl die bestehende TLS-Verbindung fälschlicherweise wiederverwendet, erfordert die zweite Anfrage keinen weiteren TLS-Handshake. Folglich wird das ungültige Passwort für den privaten Schlüssel nie benötigt, um eine neue TLS-Verbindung aufzubauen, und die Anfrage ist erfolgreich.
Das PoC demonstriert somit die Bedingung der Verbindungswiederverwendung, die mit CVE-2026-8932 verbunden ist.
| Eigenschaft | Wert |
|---|---|
| CVE | CVE-2026-8932 |
| Komponente | libcurl |
| Schwachstellentyp | Unvollständige Übereinstimmung der mTLS-Konfiguration |
| CWE | CWE-305 — Authentication Bypass by Primary Weakness |
| Betroffener Bereich | TLS-Verbindungswiederverwendung |
| Protokoll | HTTPS / mTLS |
| Client | libcurl API |
| curl CLI | Nicht betroffen |
| PoC-Umfang | Lokale Laborumgebung |
Die Schwachstelle ist ein Logik-/Konfigurationsübereinstimmungsproblem und keine traditionelle Speichersicherheitslücke wie ein Pufferüberlauf oder Use-after-Free.
libcurl verwaltet Verbindungsinformationen und kann eine bestehende Verbindung wiederverwenden, wenn eine nachfolgende Anfrage als mit der Konfiguration der Verbindung kompatibel angesehen wird.
Für TLS-Verbindungen muss die Verbindungskonfiguration daher vor der Wiederverwendung sorgfältig verglichen werden.
Die anfällige Implementierung berücksichtigte nicht alle relevanten mTLS-Konfigurationsfelder in der Logik zum Verbindungsabgleich.
Zu den betroffenen Einstellungen gehören:
cert_type
key
key_type
key_passwd
key_blob
Die wichtige Einstellung, die von diesem PoC verwendet wird, ist:
key_passwd
Das PoC baut eine TLS-Verbindung unter Verwendung eines verschlüsselten privaten Client-Schlüssels und des korrekten Passworts auf:
correct-password
Anschließend führt es eine weitere Anfrage mit demselben Zertifikat und Schlüssel aus, ändert jedoch das Passwort zu:
WRONG-PASSWORD
Eine anfällige Implementierung des Verbindungsabgleichs kann die bestehende Verbindung weiterhin als wiederverwendbar betrachten.
Der Test besteht aus zwei HTTP-Anfragen.
Die erste Anfrage baut die TLS-Verbindung auf:
URL:
https://server.test:8443/A
Client certificate:
client.crt
Private key:
client.key
Key password:
correct-password
Die TLS-Verbindung bleibt bestehen, da der Server HTTP-Keep-Alive unterstützt.
Die zweite Anfrage verwendet dasselbe Zertifikat und denselben privaten Schlüssel, ändert jedoch das Schlüsselpasswort:
URL:
https://server.test:8443/B
Client certificate:
client.crt
Private key:
client.key
Key password:
WRONG-PASSWORD
Wenn libcurl eine neue TLS-Verbindung erstellt, sollte das Laden des verschlüsselten privaten Schlüssels mit dem falschen Passwort fehlschlagen.
Wenn libcurl jedoch die bestehende Verbindung fälschlicherweise wiederverwendet, ist kein neuer TLS-Handshake erforderlich.
Das ungültige Passwort verhindert daher nicht, dass die HTTP-Anfrage erfolgreich ist.
Der Laboraufbau besteht aus:
localhost
|
v
+---------------------+
| Python mTLS Server |
| 127.0.0.1:8443 |
+----------+----------+
|
| HTTPS / TLS 1.3
|
+--------+--------+
| |
/A /B
\ /
\ /
v v
Same TLS Connection
|
v
libcurl
PoC (C)
Die wichtige Beobachtung ist, dass /A und /B auf der selben TLS-Verbindung eintreffen müssen.
CVE-2026-8932-PoC/
├── README.md
├── LICENSE
├── .gitignore
│
├── certs/
│ └── .gitkeep
│
├── poc/
│ └── poc.c
│
├── server/
│ └── server.py
│
└── docs/
├── CVE-2026-8932-POC.jpg
├── CVE-2026-8932-server-POC.jpg
├── poc-output.txt
└── server-output.txt
Das Verzeichnis certs/ wird im Repository absichtlich leer gehalten. Zertifikate und private Schlüssel sollten lokal generiert werden.
Das PoC wurde in der folgenden Umgebung getestet:
OS:
Debian GNU/Linux 13 (trixie)
Architecture:
x86_64
libcurl:
8.14.1
OpenSSL:
3.5.7
GCC:
14.2.0
Die für die Reproduktion verwendete anfällige libcurl-Installation war:
libcurl/8.14.1
Überprüfen Sie die installierte Version:
curl --version
und:
pkg-config --modversion libcurl
mkdir -p ~/cve-2026-8932-lab/{certs,poc,server,docs}
cd ~/cve-2026-8932-lab
cd ~/cve-2026-8932-lab/certs
openssl genrsa -out ca.key 2048
openssl req -x509 -new -nodes \
-key ca.key \
-sha256 \
-days 3650 \
-subj "/CN=CVE-2026-8932-CA" \
-out ca.crt
Generieren Sie den privaten Serverschlüssel:
openssl genrsa -out server.key 2048
Generieren Sie den CSR:
openssl req -new \
-key server.key \
-subj "/CN=server.test" \
-out server.csr
Erstellen Sie die Zertifikatserweiterungen:
printf "subjectAltName=DNS:server.test\nextendedKeyUsage=serverAuth\n" \
> server.ext
Signieren Sie das Zertifikat mit der Test-CA:
openssl x509 -req \
-in server.csr \
-CA ca.crt \
-CAkey ca.key \
-CAcreateserial \
-out server.crt \
-days 3650 \
-sha256 \
-extfile server.ext
Generieren Sie den privaten Client-Schlüssel:
openssl genrsa -out client.key.tmp 2048
Generieren Sie den CSR:
openssl req -new \
-key client.key.tmp \
-subj "/CN=Client-A" \
-out client.csr
Konvertieren Sie den privaten Schlüssel in das verschlüsselte PKCS#8-Format:
openssl pkcs8 \
-topk8 \
-in client.key.tmp \
-out client.key \
-v2 aes-256-cbc \
-passout pass:correct-password
Der resultierende private Schlüssel ist verschlüsselt mit:
correct-password
Erstellen Sie die Client-Zertifikatserweiterungen:
printf "extendedKeyUsage=clientAuth\n" \
> client.ext
Signieren Sie das Client-Zertifikat:
openssl x509 -req \
-in client.csr \
-CA ca.crt \
-CAkey ca.key \
-CAcreateserial \
-out client.crt \
-days 3650 \
-sha256 \
-extfile client.ext
Zu diesem Zeitpunkt sollten die erforderlichen Dateien vorhanden sein:
certs/
├── ca.crt
├── ca.key
├── client.crt
├── client.key
├── server.crt
└── server.key
Wechseln Sie in das Serververzeichnis:
cd ~/cve-2026-8932-lab/server
Starten Sie den Server:
python3 server.py
Der Server lauscht auf:
0.0.0.0:8443
Client-Zertifikatsauthentifizierung ist erforderlich.
Der Server hält außerdem HTTP/1.1-Verbindungen am Leben, damit libcurl die TLS-Verbindung wiederverwenden kann.
Öffnen Sie ein weiteres Terminal:
cd ~/cve-2026-8932-lab/poc
Kompilieren:
gcc -Wall -Wextra -O0 -g \
poc.c \
$(pkg-config --cflags --libs libcurl) \
-o poc
Ausführen:
./poc
Das PoC verwendet:
Client certificate : client.crt
Private key : client.key
Request A password : correct-password
Request B password : WRONG-PASSWORD
Der wichtigste clientseitige Nachweis ist:
[+] STEP 2: Request using modified mTLS configuration
[+] Key password = WRONG-PASSWORD
* Re-using existing https: connection with host server.test
> GET /B HTTP/1.1
Die Anfrage erhält dann:
< HTTP/1.1 200 OK
und das PoC meldet:
[!!!] B REQUEST SUCCEEDED
Dies ist bedeutsam, weil /B ein absichtlich ungültiges Passwort für den privaten Schlüssel verwendet.
Die wichtige Beobachtung ist nicht einfach, dass /B erfolgreich ist.
Der entscheidende Nachweis ist, dass libcurl ausdrücklich meldet:
Re-using existing https: connection
Daher muss die zweite Anfrage keinen weiteren TLS-Handshake mit der geänderten Schlüsselkonfiguration durchführen.
Die Serverausgabe liefert eine unabhängige Bestätigung der Verbindungswiederverwendung.
Die relevante Ausgabe ist:
[+] TLS connection #2
Client CN : Client-A
[+] Connection #2 Client=Client-A Request=GET /A HTTP/1.1
[+] Connection #2 Client=Client-A Request=GET /B HTTP/1.1
Die wichtige Beobachtung ist:
/A -> Connection #2
/B -> Connection #2
Beide HTTP-Anfragen wurden daher über dieselbe TLS-Verbindung empfangen.
Der Server meldet außerdem dieselbe Client-Identität:
Client-A
für beide Anfragen.
Der vom PoC verwendete private Schlüssel ist verschlüsselt.
Die erste Anfrage verwendet:
correct-password
was libcurl/OpenSSL den Zugriff auf den privaten Schlüssel und den Aufbau der TLS-Verbindung ermöglicht.
Die zweite Anfrage ändert die Konfiguration zu:
WRONG-PASSWORD
Wenn eine neue TLS-Verbindung aufgebaut werden müsste, müsste libcurl den verschlüsselten privaten Schlüssel erneut verarbeiten, und das falsche Passwort sollte dazu führen, dass der Vorgang fehlschlägt.
Wenn jedoch die bestehende TLS-Verbindung wiederverwendet wird, ist die TLS-Sitzung bereits aufgebaut.
Für /B ist kein neuer Client-Authentifizierungsvorgang erforderlich.
Konzeptionell:
Request A
|
| correct-password
v
TLS handshake
|
v
Established TLS connection
|
+----------------------+
| |
v v
/A /B
|
WRONG-PASSWORD
|
X
No new TLS handshake
|
v
HTTP succeeds
Dieses PoC demonstriert Verbindungswiederverwendung, nicht TLS-Sitzungswiederaufnahme.
Die beiden Mechanismen sind unterschiedlich.
Eine bereits aufgebaute TLS-Verbindung bleibt offen und wird für eine weitere HTTP-Anfrage verwendet:
TLS connection #2
|
+-- GET /A
|
+-- GET /B
Es ist kein zweiter TLS-Handshake erforderlich.
Es wird eine neue TCP/TLS-Verbindung erstellt, aber kryptografische Sitzungsinformationen aus einer früheren Verbindung werden verwendet, um den neuen TLS-Handshake zu verkürzen.
Darauf stützt sich dieses PoC nicht.
Das PoC teilt absichtlich:
CURL_LOCK_DATA_CONNECT
zwischen den beiden Easy-Handles, während es nicht teilt:
CURL_LOCK_DATA_SSL_SESSION
Dies hält die Demonstration auf die Verbindungswiederverwendung fokussiert.
Das Repository enthält aufgezeichnete Ausgaben der erfolgreichen Reproduktion.

Die aufgezeichnete Ausgabe demonstriert:
/A-AnfrageRe-using existing https: connection/B-AnfrageDie vollständige Terminalausgabe ist auch verfügbar in:
docs/poc-output.txt

Der serverseitige Nachweis demonstriert, dass:
/A -> TLS connection #2
/B -> TLS connection #2
Die vollständige Serverausgabe ist verfügbar in:
docs/server-output.txt
Wenn vor der Ausführung des PoC ein manueller curl-Test durchgeführt wird, zeigt der Server möglicherweise eine frühere Verbindung an:
TLS connection #1
Diese Verbindung steht nicht im Zusammenhang mit der tatsächlichen PoC-Ausführung.
Zum Beispiel kann die manuelle Validierungsanfrage:
curl \
--resolve server.test:8443:127.0.0.1 \
--cacert ~/cve-2026-8932-lab/certs/ca.crt \
--cert ~/cve-2026-8932-lab/certs/client.crt \
--key ~/cve-2026-8932-lab/certs/client.key \
--pass correct-password \
https://server.test:8443/A
Verbindung #1 erstellen.
Das eigentliche PoC kann dann Verbindung #2 erstellen.
Die relevante Bedingung ist daher nicht die absolute Verbindungsnummer, sondern dass:
/A and /B
während der PoC-Ausführung auf der selben TLS-Verbindung erscheinen.
Der Upstream-Fix ist:
7541ae569d82fb308a5e2d94916027da4fa3ba3e
Commit:
tls: fix incomplete mTLS config in conn reuse and session cache
Der Fix fügt die fehlenden mTLS-Konfigurationsvergleiche zur Logik des Verbindungsabgleichs hinzu.
Konzeptionell berücksichtigt die Abgleichslogik nun Werte wie:
blobcmp(c1->key_blob, c2->key_blob) &&
curl_strequal(c1->cert_type, c2->cert_type) &&
Curl_safecmp(c1->key, c2->key) &&
curl_strequal(c1->key_type, c2->key_type) &&
!Curl_timestrcmp(c1->key_passwd, c2->key_passwd)
Die wichtige Änderung für dieses PoC ist der Vergleich von:
key_passwd
Eine Änderung des Passworts für den privaten Schlüssel sollte daher verhindern, dass die bestehende Verbindung als kompatibel für die Wiederverwendung angesehen wird.
Der Upstream-Fix führte außerdem eine Regressionsabdeckung für das Verhalten des TLS-Konfigurationsabgleichs ein.
Der relevante Test ist verbunden mit:
test 3303
Die Regressionstests decken Unterschiede in der mTLS-Konfiguration ab, einschließlich:
key_passwd
key
key_type
cert_type
Zum Beispiel sollten identische Konfigurationen übereinstimmen:
config A == config B
während eine Änderung des Schlüsselpassworts dies nicht sollte:
config A key_passwd = password-A
config B key_passwd = password-B
↓
connection match = false
Dies ist dieselbe Konfigurationsdimension, die von diesem PoC ausgeübt wird.
/B schlägt fehlWenn /B fehlschlägt, prüfen Sie zunächst, ob libcurl die Verbindung tatsächlich wiederverwendet hat.
Die ausführliche Ausgabe sollte enthalten:
Re-using existing https: connection
Wenn diese Zeile nicht erscheint, wurde die Schwachstellenbedingung nicht demonstriert.
/A und /B erscheinen auf verschiedenen TLS-VerbindungenDer Server sollte anzeigen:
Connection #X -> /A
Connection #X -> /B
Wenn Sie stattdessen sehen:
Connection #X -> /A
Connection #Y -> /B
dann hat die zweite Anfrage eine neue TLS-Verbindung erstellt und die beabsichtigte Bedingung wurde nicht reproduziert.
Prüfen Sie, dass:
CURL_LOCK_DATA_CONNECT geteilt wird.CURLOPT_FORBID_REUSE nicht aktiviert ist.CURLOPT_FRESH_CONNECT nicht aktiviert ist.Connection: keep-alive sendet.Der private Client-Schlüssel muss generiert werden mit:
correct-password
Das PoC verwendet dann absichtlich:
WRONG-PASSWORD
Ändern Sie nicht das in den Befehl zur Generierung des privaten Schlüssels eingebettete Passwort, es sei denn, der entsprechende PoC-Wert wird ebenfalls geändert.
Dieses Repository ist für kontrollierte Sicherheitsforschung und Schwachstellenreproduktion gedacht.
Das PoC ist dafür ausgelegt, gegen einen lokal gehosteten Testserver zu arbeiten:
127.0.0.1:8443
Verwenden Sie das PoC nicht gegen Systeme ohne Autorisierung.
Private Schlüssel und generierte Zertifikate sollten außerhalb der Versionskontrolle bleiben.
Das Repository sollte nur enthalten:
certs/.gitkeep
anstelle generierter privater Schlüssel.
PoC-Design, Labormethodik, Implementierung und technische Analyse wurden von AliReza mit Unterstützung von OpenAI ChatGPT (GPT-5.6 Luna) entwickelt.
Menschliche Verifikation, Ausführung, Tests und Reproduktion wurden vom Repository-Autor durchgeführt.
Dieses Repository wird für Sicherheitsforschung, Schwachstellenanalyse und Bildungszwecke bereitgestellt.
Verwenden Sie es nur in Systemen und Umgebungen, für die Sie ausdrückliche Autorisierung haben.