Bug 2462083 (CVE-2026-70367) - CVE-2026-70367 stunnel: SSRF bypass in stunnel SOCKS proxy via IPv4-mapped IPv6 loopback and unspecified addresses allows access to loopback-only services
Summary: CVE-2026-70367 stunnel: SSRF bypass in stunnel SOCKS proxy via IPv4-mapped IP...
Keywords:
Status: NEW
Alias: CVE-2026-70367
Product: Security Response
Classification: Other
Component: vulnerability
Version: unspecified
Hardware: All
OS: Linux
medium
medium
Target Milestone: ---
Assignee: Product Security DevOps Team
QA Contact:
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2026-04-26 18:12 UTC by OSIDB Bzimport
Modified: 2026-08-04 10:30 UTC (History)
3 users (show)

Fixed In Version:
Clone Of:
Environment:
Last Closed:
Embargoed:


Attachments (Terms of Use)

Description OSIDB Bzimport 2026-04-26 18:12:32 UTC
AI_ONLY_REPORT
package: stunnel-5.72-8.el10
------
Summary: SSRF Bypass in SOCKS Proxy via 0.0.0.0 and IPv4-mapped IPv6  
Addresses: `stunnel` configured with `protocol = socks` rejects only  
`127.0.0.0/8` and `::1`, allowing a client to bypass the localhost filter  
via `::ffff:127.0.0.1` and, on some platforms, `0.0.0.0` or `::` to reach  
loopback-only services on the stunnel host.
Requirements to exploit: The package must be deployed in SOCKS server mode  
(`protocol = socks`), the attacker must be able to reach that listener, and  
a service of interest must be bound to loopback on the stunnel host. Some  
deployments may additionally gate access with network policy or TLS client  
authentication. The strongest reproduced bypass uses `::ffff:127.0.0.1`;  
the `0.0.0.0` and `::` variants are additional edge cases and may be  
OS-dependent.
Component affected: `stunnel-5.72-8.el10`, `src/protocol.c`,  
`validate_connect_addr()` in the SOCKS server request path
Version affected: `stunnel-5.72-8.el10` when configured with `protocol =  
socks`
Patch available: no released package fix established; proposed patch  
included below
Version fixed: unknown
Upstream coordination: Not notified.
CVSS: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:L - 8.1 (HIGH)
AV:N - A reachable `protocol = socks` listener can be attacked over the  
network with a crafted SOCKS request.
AC:L - The bypass only requires a crafted destination address and no  
race or unusual precondition once the listener is reachable.
PR:N - The SOCKS server path accepts the `0x00` no-authentication  
method; no prior privileges on the host are required.
UI:N - No user interaction is required.
S:U - The issue is an access-control failure in stunnel's own  
destination validation and is scored within that service boundary.
C:H - Successful exploitation can expose loopback-only administrative,  
metadata, or data-bearing services that were intentionally not  
network-reachable.
I:L - Some local services may accept state-changing requests once the  
loopback-only boundary is bypassed, but that impact is deployment-dependent.
A:L - Unintended requests to local services can also create limited  
service disruption or load.
Impact: Important. When `stunnel` is deployed as a reachable SOCKS server,  
a client that can reach the listener can bypass the intended localhost  
restriction and access services that should only be reachable from the  
local host. Under Red Hat's guidance this is closer to Important than  
Moderate because it can expose protected resources to a remote client of  
the vulnerable service and may enable limited integrity or availability  
impact as a follow-on. It is not Critical because it does not by itself  
provide system compromise or code execution, and it is limited to the  
supported but non-default `protocol = socks` configuration.
Embargo: no
Reason: The issue is limited to deployments that intentionally enable  
`protocol = socks`, and operators can immediately reduce exposure by  
disabling or tightly restricting the SOCKS listener. It is serious for  
affected deployments, but it is not a default-path or wormable compromise.
Acknowledgement: Aisle Research
Vulnerability Details: The directly observed flaw is an incomplete  
destination filter in `validate_connect_addr()`. The function rejects IPv4  
loopback (`127.0.0.0/8`) and exact IPv6 loopback (`::1`), but it does not  
reject IPv4-mapped IPv6 loopback such as `::ffff:127.0.0.1`, and it also  
leaves the unspecified addresses `0.0.0.0` and `::` unchecked.
```c
NOEXPORT int validate_connect_addr(CLI *c) {
#ifdef USE_IPv6
const unsigned char ipv6_loopback[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
#endif
unsigned i;
for(i=0; i<c->connect_addr.num; ++i) {
SOCKADDR_UNION *addr=&c->connect_addr.addr[i];
#ifdef USE_IPv6
if(addr->sa.sa_family==AF_INET6) {
if(!memcmp(&addr->in6.sin6_addr, ipv6_loopback, 16)) {
s_log(LOG_ERR,
"SOCKS connection to the IPv6 loopback rejected");
return 0;
}
/* TODO: implement more checks */
} else
#endif
if(addr->sa.sa_family==AF_INET) {
if((ntohl(addr->in.sin_addr.s_addr)&0xff000000)==0x7f000000) {
s_log(LOG_ERR,
"SOCKS connection to the IPv4 loopback rejected");
return 0;
}
/* TODO: implement more checks */
} else {
s_log(LOG_ERR, "Unsupported address type 0x%02x",
addr->sa.sa_family);
return 0;
}
}
return 1;
}
```
The same validation helper is used before the normal outbound connect path  
(`connect_remote()` -> `s_connect()` -> `connect()`). As a result, a client  
can supply `::ffff:127.0.0.1` and reach a service bound only to loopback on  
the stunnel host. The `0.0.0.0` and `::` variants should be treated more  
cautiously because their behavior is OS-dependent, but they remain  
unfiltered edge cases. The strongest reproduced case is the IPv4-mapped  
IPv6 loopback path on IPv6-enabled builds. The downstream impact depends on  
what services are bound to loopback and whether those services apply their  
own authentication.
Steps to reproduce:
1. Configure stunnel SOCKS server:
```ini
[socks_server]
protocol = socks
accept = 127.0.0.1:9080
cert = stunnel.pem
key = stunnel.key
```
2. Start a localhost-only target service on the same host:
```bash
nc -lv 127.0.0.1 18080
```
3. Open a TLS session to stunnel and perform SOCKS5 handshake:
```bash
openssl s_client -quiet -connect 127.0.0.1:9080
```
4. Send method negotiation bytes `05 01 00`.
5. Send a connect request to `::ffff:127.0.0.1:18080`: `05 01 00 04  
00000000000000000000ffff7f000001 46a0`
6. Observe stunnel replies success (`REP=0x00`) and data reaches the  
localhost listener.
7. Repeat with `0.0.0.0` / `::` as additional edge cases; these may be  
OS-dependent, while IPv4-mapped IPv6 loopback is the strongest reproducible  
bypass case.
Mitigation: If SOCKS proxying is not required, disable `protocol = socks`.  
Otherwise do not expose the SOCKS listener to untrusted clients, keep it  
bound to loopback or a trusted management network where possible, and  
enforce any available client-authentication or network ACL controls until a  
code fix is shipped.
Proposed Fix: A minimal fix is to reject IPv4 and IPv6 unspecified  
addresses and to detect IPv4-mapped IPv6 loopback before returning success  
from `validate_connect_addr()`.
```diff
diff --git a/src/protocol.c b/src/protocol.c
@@
NOEXPORT int validate_connect_addr(CLI *c) {
#ifdef USE_IPv6
const unsigned char  
ipv6_loopback[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1};
+    const unsigned char ipv6_any[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
#endif
@@
#ifdef USE_IPv6
if(addr->sa.sa_family==AF_INET6) {
if(!memcmp(&addr->in6.sin6_addr, ipv6_loopback, 16)) {
s_log(LOG_ERR,
"SOCKS connection to the IPv6 loopback rejected");
return 0;
}
+            if(!memcmp(&addr->in6.sin6_addr, ipv6_any, 16)) {
+                s_log(LOG_ERR,
+                    "SOCKS connection to the IPv6 unspecified address  
rejected");
+                return 0;
+            }
+            if(!memcmp(addr->in6.sin6_addr.s6_addr,
+                    "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff",  
12) &&
+                    ((addr->in6.sin6_addr.s6_addr[12] & 0xff)==0x7f)) {
+                s_log(LOG_ERR,
+                    "SOCKS connection to the IPv4-mapped IPv6 loopback  
rejected");
+                return 0;
+            }
/* TODO: implement more checks */
} else
#endif
if(addr->sa.sa_family==AF_INET) {
+            if(ntohl(addr->in.sin_addr.s_addr)==0x00000000) {
+                s_log(LOG_ERR,
+                    "SOCKS connection to the IPv4 unspecified address  
rejected");
+                return 0;
+            }
if((ntohl(addr->in.sin_addr.s_addr)&0xff000000)==0x7f000000) {
s_log(LOG_ERR,
"SOCKS connection to the IPv4 loopback rejected");
return 0;
}
```
------
This report was generated using AI technology. Always review AI-generated  
content prior to use


Note You need to log in before you can comment on or make changes to this bug.