HexBrain

curl · Report #3786077

SOCKS5 no-auth accepted despite username/password-only authentication

N/Astatus
mediumseverity
10upvotes
9 Jun 2026disclosed

How it was found

Summary:

curl/libcurl appears to allow unauthenticated SOCKS5 negotiation even when the caller explicitly configures username/password-only SOCKS5 authentication. With --socks5-basic and SOCKS5 credentials set, curl still advertises both SOCKS5 method 0x00 (no authentication) and 0x02 (username/password). If the proxy selects 0x00, curl proceeds with the transfer without performing username/password authentication. This appears to contradict the documented CURLOPT_SOCKS5_AUTH behaviour, where CURLAUTH_BASIC allows username/password authentication and CURLAUTH_NONE is the flag that allows no authentication. The impact is a caller-policy bypass: an application or operator may believe SOCKS5 username/password authentication is required, while the transfer can still complete through unauthenticated SOCKS5.

Affected version

Reproduced against current curl source:

Repository: https://github.com/curl/curl.git
Commit: d3e9a815c4a68099b774742073c50b996d69fcd6
Commit date: 2026-06-05T16:57:38+02:00
Commit subject: tidy-up: miscellaneous

curl -V output from the validation build:

curl 8.21.0-DEV (Linux) libcurl/8.21.0-DEV OpenSSL/3.5.5 zlib/1.3.1 brotli/1.2.0 zstd/1.5.7 libidn2/2.3.8 libpsl/0.21.2 libssh2/1.11.1 nghttp2/1.68.0 OpenLDAP/2.6.10
Release-Date: [unreleased]
Protocols: dict file ftp ftps gopher gophers http https imap imaps ipfs ipns ldap ldaps mqtt mqtts pop3 pop3s rtsp scp sftp smtp smtps telnet tftp ws wss
Features: alt-svc AsynchDNS brotli Debug HSTS HTTP2 HTTPS-proxy HTTPSRR IDN IPv6 Largefile libz PSL SSL threadsafe TLS-SRP UnixSockets zstd

Test platform: Linux local validation harness.

Steps To Reproduce:

I used a minimal local SOCKS5 proxy fixture that records curl’s initial SOCKS5 greeting and then chooses which authentication method to select.

The curl invocation used SOCKS5 username/password credentials and requested username/password SOCKS5 authentication with:

--socks5-basic

The relevant expectation is:

CURLOPT_SOCKS5_AUTH tells libcurl which SOCKS5 authentication methods are allowed.
CURLAUTH_BASIC allows username/password authentication.
CURLAUTH_NONE allows no authentication.
--socks5-basic maps to CURLOPT_SOCKS5_AUTH=CURLAUTH_BASIC.

Observed SOCKS5 greeting:

05 02 00 02

Interpreted as:

05       SOCKS version 5
02       two methods offered
00       no authentication
02       username/password

So curl advertises both no-auth and username/password even though username/password-only SOCKS5 auth was configured.

Case 1: proxy selects no-auth:

Proxy selected: 0x00
Result: curl proceeded to the HTTP request.
Username/password exchange: none.
Transfer: successful.

Runtime transcript:

CASE choice=0x00 exit=0 stdout=b'OK' stderr=b'' methods=['0x00', '0x02'] greeting=05020002 auth=None http_seen=True

Case 2: proxy selects username/password:

Proxy selected: 0x02
Result: curl performed the expected username/password authentication exchange.
Transfer: successful.

Runtime transcript:

CASE choice=0x02 exit=0 stdout=b'OK' stderr=b'' methods=['0x00', '0x02'] greeting=05020002 auth=('user', 'pass') http_seen=True

Expected behaviour:

When configured with username/password-only SOCKS5 authentication, curl should not advertise method 0x00 no-auth.
If a proxy selects a method that was not allowed by the caller's SOCKS5 auth configuration, curl should reject the negotiation.

Observed behaviour:

curl advertises no-auth and accepts no-auth when selected by the proxy.

I can provide the minimal local proxy fixture and full runtime evidence bundle as a seperate attachment if useful.

Impact

The issue is not that a proxy can choose no-auth. The issue is that curl offers no-auth even after the caller has explicitly asked for username/password SOCKS5 authentication. (!)

As I understand the API, CURLOPT_SOCKS5_AUTH is not just a preference hint. It defines which SOCKS5 authentication methods libcurl is allowed to use. CURLAUTH_BASIC means username/password. CURLAUTH_NONE is the separate option for unauthenticated SOCKS5.

So when a caller uses --socks5-basic or CURLOPT_SOCKS5_AUTH=CURLAUTH_BASIC, they are making a security decision: do not proceed through unauthenticated SOCKS5.

The observed behaviour breaks that expectation. curl still offers 0x00 no-auth on the wire, and if the proxy selects it, curl continues without the username/password exchange.

This would be a real problem on for systems (like ours) where authenticated proxy use is part of the security model, for example auditability, routing policy, tenant separation, delegation or proxy-side authorisation. In those cases, curl can silently take a weaker path than the caller configured.

Also if this is part of a security policy anywhere it's not doing the secure thing intended.

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