CVE-2026-8932 的概念验证复现,该漏洞是 libcurl 连接复用中 mTLS 配置匹配不完整的问题。
CVE-2026-8932 影响 libcurl 的连接复用逻辑,当请求之间的双向 TLS(mTLS)配置发生变化时会出现问题。
在存在漏洞的条件下,即使与 mTLS 相关的配置选项已更改且本应阻止该连接被复用,libcurl 仍可能复用现有的 TLS 连接。
本 PoC 通过在使用相同客户端证书和私钥的情况下,在两个请求之间更改私钥密码来演示该问题。
第一个请求使用正确的密码:
correct-password
第二个请求故意使用无效的密码:
WRONG-PASSWORD
如果 libcurl 错误地复用了现有的 TLS 连接,则第二个请求不需要再进行一次 TLS 握手。因此,建立新的 TLS 连接时根本不需要使用无效的私钥密码,请求便会成功。
因此,本 PoC 演示了与 CVE-2026-8932 相关的连接复用条件。
| 属性 | 值 |
|---|---|
| CVE | CVE-2026-8932 |
| 组件 | libcurl |
| 漏洞类型 | mTLS 配置匹配不完整 |
| CWE | CWE-305 — 通过主要弱点绕过身份验证 |
| 受影响区域 | TLS 连接复用 |
| 协议 | HTTPS / mTLS |
| 客户端 | libcurl API |
| curl CLI | 不受影响 |
| PoC 范围 | 本地实验室环境 |
该漏洞是一个逻辑/配置匹配问题,而非传统的内存安全漏洞(如缓冲区溢出或释放后使用)。
libcurl 维护连接信息,当后续请求被认为与连接的配置兼容时,可以复用现有连接。
因此,对于 TLS 连接,在复用之前必须仔细比较连接配置。
存在漏洞的实现未将所有相关的 mTLS 配置字段纳入连接匹配逻辑。
受影响的设置包括:
cert_type
key
key_type
key_passwd
key_blob
本 PoC 使用的重要设置是:
key_passwd
本 PoC 使用加密的客户端私钥和正确的密码建立 TLS 连接:
correct-password
然后使用相同的证书和密钥执行另一个请求,但将密码更改为:
WRONG-PASSWORD
存在漏洞的连接匹配实现可能仍会认为现有连接可复用。
测试由两个 HTTP 请求组成。
第一个请求建立 TLS 连接:
URL:
https://server.test:8443/A
Client certificate:
client.crt
Private key:
client.key
Key password:
correct-password
由于服务器支持 HTTP keep-alive,TLS 连接保持持久。
第二个请求使用相同的证书和私钥,但更改了密钥密码:
URL:
https://server.test:8443/B
Client certificate:
client.crt
Private key:
client.key
Key password:
WRONG-PASSWORD
如果 libcurl 创建新的 TLS 连接,使用错误密码加载加密私钥应当失败。
然而,如果 libcurl 错误地复用了现有连接,则不需要新的 TLS 握手。
因此,无效的密码不会阻止 HTTP 请求成功。
实验室环境由以下部分组成:
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)
重要的观察结果是 /A 和 /B 必须到达同一个 TLS 连接。
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
certs/ 目录在仓库中故意保持为空。证书和私钥应在本地生成。
本 PoC 在以下环境中测试:
OS:
Debian GNU/Linux 13 (trixie)
Architecture:
x86_64
libcurl:
8.14.1
OpenSSL:
3.5.7
GCC:
14.2.0
用于复现的存在漏洞的 libcurl 安装版本为:
libcurl/8.14.1
验证已安装的版本:
curl --version
以及:
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
生成服务器私钥:
openssl genrsa -out server.key 2048
生成 CSR:
openssl req -new \
-key server.key \
-subj "/CN=server.test" \
-out server.csr
创建证书扩展:
printf "subjectAltName=DNS:server.test\nextendedKeyUsage=serverAuth\n" \
> server.ext
使用测试 CA 签署证书:
openssl x509 -req \
-in server.csr \
-CA ca.crt \
-CAkey ca.key \
-CAcreateserial \
-out server.crt \
-days 3650 \
-sha256 \
-extfile server.ext
生成客户端私钥:
openssl genrsa -out client.key.tmp 2048
生成 CSR:
openssl req -new \
-key client.key.tmp \
-subj "/CN=Client-A" \
-out client.csr
将私钥转换为加密的 PKCS#8 格式:
openssl pkcs8 \
-topk8 \
-in client.key.tmp \
-out client.key \
-v2 aes-256-cbc \
-passout pass:correct-password
生成的私钥使用以下密码加密:
correct-password
创建客户端证书扩展:
printf "extendedKeyUsage=clientAuth\n" \
> client.ext
签署客户端证书:
openssl x509 -req \
-in client.csr \
-CA ca.crt \
-CAkey ca.key \
-CAcreateserial \
-out client.crt \
-days 3650 \
-sha256 \
-extfile client.ext
此时所需文件应已存在:
certs/
├── ca.crt
├── ca.key
├── client.crt
├── client.key
├── server.crt
└── server.key
进入服务器目录:
cd ~/cve-2026-8932-lab/server
启动服务器:
python3 server.py
服务器监听:
0.0.0.0:8443
需要客户端证书身份验证。
服务器还保持 HTTP/1.1 连接活跃,以便 libcurl 可以复用 TLS 连接。
打开另一个终端:
cd ~/cve-2026-8932-lab/poc
编译:
gcc -Wall -Wextra -O0 -g \
poc.c \
$(pkg-config --cflags --libs libcurl) \
-o poc
执行:
./poc
本 PoC 使用:
Client certificate : client.crt
Private key : client.key
Request A password : correct-password
Request B password : WRONG-PASSWORD
最重要的客户端证据是:
[+] 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
随后请求收到:
< HTTP/1.1 200 OK
并且 PoC 报告:
[!!!] B REQUEST SUCCEEDED
这一点很重要,因为 /B 使用了故意无效的私钥密码。
关键观察不仅仅是 /B 成功。
关键证据是 libcurl 明确报告:
Re-using existing https: connection
因此,第二个请求不需要使用修改后的密钥配置执行另一次 TLS 握手。
服务器输出提供了连接复用的独立确认。
相关输出为:
[+] 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
重要的观察结果是:
/A -> Connection #2
/B -> Connection #2
因此,两个 HTTP 请求都是通过同一个 TLS 连接接收的。
服务器还报告了两个请求的相同客户端身份:
Client-A
本 PoC 使用的私钥是加密的。
第一个请求使用:
correct-password
这允许 libcurl/OpenSSL 访问私钥并建立 TLS 连接。
第二个请求将配置更改为:
WRONG-PASSWORD
如果必须建立新的 TLS 连接,libcurl 将需要再次处理加密的私钥,而错误的密码应导致操作失败。
然而,当复用现有的 TLS 连接时,TLS 会话已经建立。
/B 不需要新的客户端身份验证操作。
概念上:
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
本 PoC 演示的是连接复用,而非 TLS 会话恢复。
这两种机制是不同的。
已建立的 TLS 连接保持打开,并用于另一个 HTTP 请求:
TLS connection #2
|
+-- GET /A
|
+-- GET /B
不需要第二次 TLS 握手。
创建新的 TCP/TLS 连接,但使用来自较早连接的加密会话信息来缩短新的 TLS 握手。
这不是本 PoC 所依赖的机制。
本 PoC 故意在两个 easy handle 之间共享:
CURL_LOCK_DATA_CONNECT
而不共享:
CURL_LOCK_DATA_SSL_SESSION
这将演示重点保持在连接复用上。
仓库包含成功复现时捕获的输出。

捕获的输出演示了:
/A 请求Re-using existing https: connection/B 请求完整的终端输出也可在以下位置获取:
docs/poc-output.txt

服务器端证据表明:
/A -> TLS connection #2
/B -> TLS connection #2
完整的服务器输出可在以下位置获取:
docs/server-output.txt
如果在运行 PoC 之前执行手动 curl 测试,服务器可能会显示较早的连接:
TLS connection #1
此连接与实际 PoC 执行无关。
例如,手动验证请求:
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
可能会创建连接 #1。
实际的 PoC 随后可能会创建连接 #2。
因此,相关条件不是绝对的连接编号,而是:
/A and /B
在 PoC 执行期间出现在同一个 TLS 连接上。
上游修复为:
7541ae569d82fb308a5e2d94916027da4fa3ba3e
提交:
tls: fix incomplete mTLS config in conn reuse and session cache
该修复将缺失的 mTLS 配置比较添加到连接匹配逻辑中。
概念上,匹配逻辑现在会考虑包括以下值:
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)
对本 PoC 而言,重要的更改是比较:
key_passwd
因此,私钥密码的更改应阻止现有连接被视为可复用。
上游修复还引入了针对 TLS 配置匹配行为的回归覆盖。
相关测试与以下内容关联:
test 3303
回归测试覆盖了 mTLS 配置的差异,包括:
key_passwd
key
key_type
cert_type
例如,相同的配置应匹配:
config A == config B
而更改密钥密码则不应匹配:
config A key_passwd = password-A
config B key_passwd = password-B
↓
connection match = false
这与本 PoC 所测试的配置维度相同。
/B 失败如果 /B 失败,首先检查 libcurl 是否实际复用了连接。
详细输出应包含:
Re-using existing https: connection
如果此行未出现,则未演示漏洞条件。
/A 和 /B 出现在不同的 TLS 连接上服务器应显示:
Connection #X -> /A
Connection #X -> /B
如果相反你看到:
Connection #X -> /A
Connection #Y -> /B
则第二个请求创建了新的 TLS 连接,未复现预期条件。
检查以下内容:
CURL_LOCK_DATA_CONNECT 已共享。CURLOPT_FORBID_REUSE 未启用。CURLOPT_FRESH_CONNECT 未启用。Connection: keep-alive。客户端私钥必须使用以下密码生成:
correct-password
然后 PoC 故意使用:
WRONG-PASSWORD
除非同时更改相应的 PoC 值,否则不要更改私钥生成命令中嵌入的密码。
本仓库旨在用于受控的安全研究和漏洞复现。
本 PoC 设计为针对本地托管的测试服务器运行:
127.0.0.1:8443
未经授权,请勿对系统使用本 PoC。
私钥和生成的证书应保持在版本控制之外。
仓库应仅包含:
certs/.gitkeep
而不是生成的私钥。
PoC 设计、实验室方法、实现和技术分析由 AliReza 在 OpenAI ChatGPT (GPT-5.6 Luna) 的协助下开发。
人工验证、执行、测试和复现由仓库作者完成。
本仓库仅供安全研究、漏洞分析和教育目的使用。
仅在您拥有明确授权的系统和环境中使用。