curl · Report #3822248
CVE-2026-13608: OpenLDAP SASL authentication bypass
How it was found
Summary:
In lib/openldap.c, oldap_state_sasl_resp() transitions to OLDAP_STOP (connection ready)
whenever Curl_sasl_continue() returns CURLE_OK with progress != SASL_INPROGRESS. This
condition does not distinguish SASL_DONE (authentication completed) from SASL_IDLE (no
mechanism available). A malicious LDAP server can send a malformed SASL challenge, causing the
client to cancel the mechanism and retry with no remaining mechanisms. Curl_sasl_start() then
returns CURLE_OK with progress == SASL_IDLE, and the connection proceeds as if authentication
succeeded. This bypasses Kerberos (GSSAPI) mutual authentication: an attacker without a valid
keytab can impersonate a server and inject arbitrary LDAP responses.
Affected version
curl 8.21.0-DEV (Linux) libcurl/8.21.0-DEV OpenSSL/3.0.13 zlib/1.3 mit-krb5/1.20.1 OpenLDAP/2.6.10
Release-Date: [unreleased]
Protocols: dict file ftp ftps gopher gophers http https imap imaps ipfs ipns ldap ldaps pop3 pop3s rtsp smtp smtps telnet tftp ws wss
Features: alt-svc AsynchDNS GSS-API HSTS HTTPS-proxy IPv6 Kerberos Largefile libz SPNEGO SSL threadsafe TLS-SRP UnixSockets
Tested on Ubuntu 24.04 (x86_64) against commit 68720b4837284335b2d63cb358f8f6ce65f5bc55 (HEAD
of master as of 2026-06-24). The vulnerable code has been present since the OpenLDAP SASL support
was introduced and is unchanged in the current release.
Platform: Linux 6.8.0, x86_64, MIT Kerberos 1.20.1, OpenLDAP 2.6.10.
Steps To Reproduce:
Prerequisites
- curl/libcurl built with OpenLDAP backend (
-DUSE_OPENLDAP=ON) and GSSAPI (-DCURL_USE_GSSAPI=ON) - A working Kerberos environment (KDC with realm,
kinitto obtain a TGT) - Python 3 (for the mock server)
Setup
# Build curl with OpenLDAP + GSSAPI
cmake -B build -DCURL_DISABLE_LDAP=OFF -DUSE_OPENLDAP=ON \
-DCURL_USE_GSSAPI=ON -DCURL_USE_OPENSSL=ON -DCURL_USE_LIBPSL=OFF \
-DCURL_USE_LIBIDN2=OFF -DCMAKE_BUILD_TYPE=Debug
cmake --build build -j$(nproc)
# Set up minimal KDC (example for MIT Kerberos)
sudo kdb5_util create -s -P testpass123 # realm: TEST.LOCAL
sudo kadmin.local -q "addprinc -pw testpass [email protected]"
sudo kadmin.local -q "addprinc -randkey ldap/[email protected]"
sudo kadmin.local -q "ktadd -k /tmp/ldap.keytab ldap/[email protected]"
sudo krb5kdc
# Obtain TGT
echo testpass | kinit [email protected]
Mock LDAP server (attacker — has NO keytab)
Run the attached mock_gssapi_server.py:
python3 mock_gssapi_server.py 3893
The server triggers SASL_CANCEL as follows:
- Advertises only GSSAPI in
supportedSASLMechanisms. - Receives the client's SASL BindRequest containing a Kerberos AP-REQ (which it cannot decrypt).
- Replies with
LDAP_SASL_BIND_IN_PROGRESS(resultCode 14) and a garbageserverSaslCredsvalue (\x60\x10\xDE\xAD...). This invalid GSSAPI token causesgss_init_sec_context()to fail, which libcurl translates toCURLE_BAD_CONTENT_ENCODING— the condition that enters theSASL_CANCELstate. - Acknowledges the subsequent cancel BindRequest with
LDAP_SUCCESS(resultCode 0).
Trigger the bug
# Ensure valid TGT exists
klist
# Connect to malicious server with GSSAPI auth
./build/src/curl --user "[email protected]:testpass" \
--login-options "AUTH=GSSAPI" \
"ldap://localhost:3893/dc=example,dc=com?*?sub" \
--connect-timeout 5 --max-time 10
Expected result (fixed behavior)
curl should report authentication failure (exit code 67, CURLE_LOGIN_DENIED).
Actual result
DN: cn=admin,dc=example,dc=com
cn: admin
uid: attacker-injected
userPassword: {CLEAR}pwned
sshPublicKey: ssh-ed25519 AAAA_ATTACKER_KEY attacker@evil
description: INJECTED via CWE-306 Kerberos bypass
Exit code: 0
curl considers the connection authenticated and proceeds to execute the LDAP query. The attacker's injected data is returned to the client as trusted LDAP results.
Root Cause
In lib/openldap.c line 786:
result = Curl_sasl_continue(&li->sasl, data, code, &progress);
if(!result && progress != SASL_INPROGRESS) // ← does not distinguish SASL_DONE from SASL_IDLE
oldap_state(data, li, OLDAP_STOP);
https://github.com/curl/curl/blob/68720b4837284335b2d63cb358f8f6ce65f5bc55/lib/openldap.c#L786-L787
When Curl_sasl_continue() enters the SASL_CANCEL case (lib/curl_sasl.c line 773-780), it
removes the failed mechanism and calls Curl_sasl_start(). If no mechanisms remain,
Curl_sasl_start() returns CURLE_OK with *progress = SASL_IDLE (line 519):
https://github.com/curl/curl/blob/68720b4837284335b2d63cb358f8f6ce65f5bc55/lib/curl_sasl.c#L519 https://github.com/curl/curl/blob/68720b4837284335b2d63cb358f8f6ce65f5bc55/lib/curl_sasl.c#L773-L780
Suggested fix
result = Curl_sasl_continue(&li->sasl, data, code, &progress);
if(!result && progress == SASL_DONE) // ← only accept explicit completion
oldap_state(data, li, OLDAP_STOP);
else if(!result && progress == SASL_IDLE)
result = CURLE_LOGIN_DENIED;
Impact
Summary:
A malicious LDAP server (or network attacker in MITM position) can bypass SASL authentication in libcurl's OpenLDAP backend by sending a single malformed SASL challenge. The most significant impact is against GSSAPI (Kerberos), where the bypass nullifies mutual authentication: the client proceeds without verifying the server holds a valid keytab. This allows the attacker to:
- Capture client queries — leaking the LDAP search base DN, filter, and requested attributes.
- Inject arbitrary LDAP results — the client accepts fabricated directory entries (e.g., forged SSH public keys, group memberships, or credentials) as trusted data.
Prerequisites:
- libcurl built with the OpenLDAP backend (
USE_OPENLDAP) and Kerberos support. - The application must configure SASL authentication (e.g.,
CURLOPT_LOGIN_OPTIONS "AUTH=GSSAPI"). - The attacker must be positioned as MITM or control the target LDAP server's address (DNS poisoning, ARP spoofing, etc.).
- The connection must not use LDAPS/TLS (or the client must not properly validate the server certificate), since TLS would independently block MITM.
The impact is highest in environments that rely on Kerberos for server identity verification on non-TLS LDAP connections.
The initial discovery was made by AI. All technical claims have been reviewed and revised by human experts.
Reporting on behalf of Autonomous Code Security (ACS) team at Microsoft.