
Prova de conceito que reproduz o CVE-2026-8932, uma falha de correspondência em configuração mTLS incompleta na reutilização de conexões do libcurl, com um servidor de laboratório local e PoC em C.
Reprodução de prova de conceito de CVE-2026-8932, um problema de correspondência incompleta de configuração mTLS na reutilização de conexões do libcurl.
CVE-2026-8932 afeta a lógica de reutilização de conexões do libcurl quando a configuração de mutual TLS (mTLS) muda entre requisições.
Em condições vulneráveis, o libcurl pode reutilizar uma conexão TLS existente mesmo que uma opção de configuração relacionada a mTLS tenha mudado e deveria ter impedido que essa conexão fosse reutilizada.
Esta PoC demonstra o problema alterando a senha da chave privada entre duas requisições, enquanto utiliza o mesmo certificado de cliente e chave privada.
A primeira requisição usa a senha correta:
correct-password
A segunda requisição usa intencionalmente uma senha inválida:
WRONG-PASSWORD
Se o libcurl reutilizar incorretamente a conexão TLS existente, a segunda requisição não exigirá outro handshake TLS. Consequentemente, a senha inválida da chave privada nunca será necessária para estabelecer uma nova conexão TLS e a requisição será bem-sucedida.
A PoC, portanto, demonstra a condição de reutilização de conexão associada a CVE-2026-8932.
| Propriedade | Valor |
|---|
| CVE | CVE-2026-8932 |
| Componente | libcurl |
| Tipo de Vulnerabilidade | Correspondência incompleta de configuração mTLS |
| CWE | CWE-305 — Authentication Bypass by Primary Weakness |
| Área Afetada | Reutilização de conexão TLS |
| Protocolo | HTTPS / mTLS |
| Cliente | API libcurl |
| CLI curl | Não afetado |
| Escopo da PoC | Ambiente de laboratório local |
A vulnerabilidade é um problema de lógica/correspondência de configuração, e não uma vulnerabilidade tradicional de segurança de memória, como buffer overflow ou use-after-free.
O libcurl mantém informações de conexão e pode reutilizar uma conexão existente quando uma requisição subsequente é considerada compatível com a configuração da conexão.
Para conexões TLS, a configuração da conexão deve, portanto, ser comparada cuidadosamente antes da reutilização.
A implementação vulnerável não incluía todos os campos relevantes de configuração mTLS na lógica de correspondência de conexão.
Entre as configurações afetadas estão:
cert_type
key
key_type
key_passwd
key_blob
A configuração importante usada por esta PoC é:
key_passwd
A PoC estabelece uma conexão TLS usando uma chave privada de cliente criptografada e a senha correta:
correct-password
Em seguida, realiza outra requisição usando o mesmo certificado e chave, mas altera a senha para:
WRONG-PASSWORD
Uma implementação vulnerável de correspondência de conexão ainda pode considerar a conexão existente reutilizável.
O teste consiste em duas requisições HTTP.
A primeira requisição estabelece a conexão TLS:
URL:
https://server.test:8443/A
Certificado do cliente:
client.crt
Chave privada:
client.key
Senha da chave:
correct-password
A conexão TLS permanece persistente porque o servidor suporta HTTP keep-alive.
A segunda requisição usa o mesmo certificado e chave privada, mas altera a senha da chave:
URL:
https://server.test:8443/B
Certificado do cliente:
client.crt
Chave privada:
client.key
Senha da chave:
WRONG-PASSWORD
Se o libcurl criar uma nova conexão TLS, o carregamento da chave privada criptografada com a senha errada deve falhar.
No entanto, se o libcurl reutilizar incorretamente a conexão existente, nenhum novo handshake TLS será necessário.
A senha inválida, portanto, não impede que a requisição HTTP seja bem-sucedida.
A configuração do laboratório consiste em:
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 observação importante é que /A e /B devem chegar na mesma conexão 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
O diretório certs/ é intencionalmente mantido vazio no repositório. Certificados e chaves privadas devem ser gerados localmente.
A PoC foi testada no seguinte ambiente:
OS:
Debian GNU/Linux 13 (trixie)
Architecture:
x86_64
libcurl:
8.14.1
OpenSSL:
3.5.7
GCC:
14.2.0
A instalação vulnerável do libcurl usada para a reprodução foi:
libcurl/8.14.1
Verifique a versão instalada:
curl --version
e:
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
Gere a chave privada do servidor:
openssl genrsa -out server.key 2048
Gere a CSR:
openssl req -new \
-key server.key \
-subj "/CN=server.test" \
-out server.csr
Crie as extensões do certificado:
printf "subjectAltName=DNS:server.test\nextendedKeyUsage=serverAuth\n" \
> server.ext
Assine o certificado usando a CA de teste:
openssl x509 -req \
-in server.csr \
-CA ca.crt \
-CAkey ca.key \
-CAcreateserial \
-out server.crt \
-days 3650 \
-sha256 \
-extfile server.ext
Gere a chave privada do cliente:
openssl genrsa -out client.key.tmp 2048
Gere a CSR:
openssl req -new \
-key client.key.tmp \
-subj "/CN=Client-A" \
-out client.csr
Converta a chave privada para o formato PKCS#8 criptografado:
openssl pkcs8 \
-topk8 \
-in client.key.tmp \
-out client.key \
-v2 aes-256-cbc \
-passout pass:correct-password
A chave privada resultante é criptografada com:
correct-password
Crie as extensões do certificado do cliente:
printf "extendedKeyUsage=clientAuth\n" \
> client.ext
Assine o certificado do cliente:
openssl x509 -req \
-in client.csr \
-CA ca.crt \
-CAkey ca.key \
-CAcreateserial \
-out client.crt \
-days 3650 \
-sha256 \
-extfile client.ext
Neste ponto, os arquivos necessários devem existir:
certs/
├── ca.crt
├── ca.key
├── client.crt
├── client.key
├── server.crt
└── server.key
Mova-se para o diretório do servidor:
cd ~/cve-2026-8932-lab/server
Inicie o servidor:
python3 server.py
O servidor escuta em:
0.0.0.0:8443
A autenticação por certificado de cliente é obrigatória.
O servidor também mantém conexões HTTP/1.1 ativas para que o libcurl possa reutilizar a conexão TLS.
Abra outro terminal:
cd ~/cve-2026-8932-lab/poc
Compile:
gcc -Wall -Wextra -O0 -g \
poc.c \
$(pkg-config --cflags --libs libcurl) \
-o poc
Execute:
./poc
A PoC usa:
Client certificate : client.crt
Private key : client.key
Request A password : correct-password
Request B password : WRONG-PASSWORD
A evidência mais importante do lado do cliente é:
[+] 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
A requisição então recebe:
< HTTP/1.1 200 OK
e a PoC reporta:
[!!!] B REQUEST SUCCEEDED
Isso é significativo porque /B usa uma senha de chave privada intencionalmente inválida.
A observação principal não é simplesmente que /B é bem-sucedida.
A evidência crítica é que o libcurl reporta explicitamente:
Re-using existing https: connection
Portanto, a segunda requisição não precisa realizar outro handshake TLS usando a configuração de chave modificada.
A saída do servidor fornece confirmação independente da reutilização da conexão.
A saída relevante é:
[+] 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 observação importante é:
/A -> Connection #2
/B -> Connection #2
Ambas as requisições HTTP foram, portanto, recebidas através da mesma conexão TLS.
O servidor também reporta a mesma identidade de cliente:
Client-A
para ambas as requisições.
A chave privada usada pela PoC é criptografada.
A primeira requisição usa:
correct-password
o que permite ao libcurl/OpenSSL acessar a chave privada e estabelecer a conexão TLS.
A segunda requisição altera a configuração para:
WRONG-PASSWORD
Se uma nova conexão TLS tivesse que ser estabelecida, o libcurl precisaria processar novamente a chave privada criptografada e a senha incorreta deveria causar falha na operação.
No entanto, quando a conexão TLS existente é reutilizada, a sessão TLS já está estabelecida.
Nenhuma nova operação de autenticação de cliente é necessária para /B.
Conceitualmente:
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
Esta PoC demonstra reutilização de conexão, não retomada de sessão TLS.
Os dois mecanismos são diferentes.
Uma conexão TLS já estabelecida permanece aberta e é usada para outra requisição HTTP:
TLS connection #2
|
+-- GET /A
|
+-- GET /B
Nenhum segundo handshake TLS é necessário.
Uma nova conexão TCP/TLS é criada, mas informações criptográficas de sessão de uma conexão anterior são usadas para encurtar o novo handshake TLS.
Não é nisso que esta PoC se baseia.
A PoC compartilha intencionalmente:
CURL_LOCK_DATA_CONNECT
entre os dois easy handles, enquanto não compartilha:
CURL_LOCK_DATA_SSL_SESSION
Isso mantém a demonstração focada na reutilização de conexão.
O repositório contém a saída capturada da reprodução bem-sucedida.

A saída capturada demonstra:
/A bem-sucedidaRe-using existing https: connection/B bem-sucedidaA saída completa do terminal também está disponível em:
docs/poc-output.txt

A evidência do lado do servidor demonstra que:
/A -> TLS connection #2
/B -> TLS connection #2
A saída completa do servidor está disponível em:
docs/server-output.txt
Se um teste manual com curl for realizado antes de executar a PoC, o servidor pode exibir uma conexão anterior:
TLS connection #1
Essa conexão não está relacionada à execução real da PoC.
Por exemplo, a requisição de validação manual:
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
pode criar a conexão #1.
A PoC real pode então criar a conexão #2.
A condição relevante, portanto, não é o número absoluto da conexão, mas que:
/A and /B
apareçam na mesma conexão TLS durante a execução da PoC.
A correção upstream é:
7541ae569d82fb308a5e2d94916027da4fa3ba3e
Commit:
tls: fix incomplete mTLS config in conn reuse and session cache
A correção adiciona as comparações de configuração mTLS ausentes à lógica de correspondência de conexão.
Conceitualmente, a lógica de correspondência agora considera valores incluindo:
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)
A mudança importante para esta PoC é a comparação de:
key_passwd
Uma alteração na senha da chave privada deve, portanto, impedir que a conexão existente seja considerada compatível para reutilização.
A correção upstream também introduziu cobertura de regressão para o comportamento de correspondência de configuração TLS.
O teste relevante está associado a:
test 3303
O teste de regressão cobre diferenças na configuração mTLS, incluindo:
key_passwd
key
key_type
cert_type
Por exemplo, configurações idênticas devem corresponder:
config A == config B
enquanto alterar a senha da chave não deve:
config A key_passwd = password-A
config B key_passwd = password-B
↓
connection match = false
Esta é a mesma dimensão de configuração exercitada por esta PoC.
/B falhaSe /B falhar, primeiro verifique se o libcurl realmente reutilizou a conexão.
A saída verbosa deve conter:
Re-using existing https: connection
Se esta linha não aparecer, a condição de vulnerabilidade não foi demonstrada.
/A e /B aparecem em conexões TLS diferentesO servidor deve mostrar:
Connection #X -> /A
Connection #X -> /B
Se, em vez disso, você vir:
Connection #X -> /A
Connection #Y -> /B
então a segunda requisição criou uma nova conexão TLS e a condição pretendida não foi reproduzida.
Verifique se:
CURL_LOCK_DATA_CONNECT está compartilhado.CURLOPT_FORBID_REUSE não está habilitado.CURLOPT_FRESH_CONNECT não está habilitado.Connection: keep-alive.A chave privada do cliente deve ser gerada usando:
correct-password
A PoC então usa intencionalmente:
WRONG-PASSWORD
Não altere a senha incorporada no comando de geração da chave privada, a menos que o valor correspondente na PoC também seja alterado.
Este repositório destina-se a pesquisa de segurança controlada e reprodução de vulnerabilidades.
A PoC foi projetada para operar contra um servidor de teste hospedado localmente:
127.0.0.1:8443
Não use a PoC contra sistemas sem autorização.
Chaves privadas e certificados gerados devem permanecer fora do controle de versão.
O repositório deve conter apenas:
certs/.gitkeep
em vez de chaves privadas geradas.
O design da PoC, a metodologia de laboratório, a implementação e a análise técnica foram desenvolvidos por AliReza com assistência do OpenAI ChatGPT (GPT-5.6 Luna).
A verificação humana, execução, testes e reprodução foram realizados pelo autor do repositório.
Este repositório é fornecido para fins de pesquisa de segurança, análise de vulnerabilidades e fins educacionais.
Use-o apenas em sistemas e ambientes para os quais você tenha autorização explícita.