← Writing

SSRF in Nym Exit Nodes

A Server-Side Request Forgery vulnerability in Nym Technologies nym-node v1.30.0 and earlier allows a remote attacker to obtain sensitive information from internal services on exit gateways via SOCKS5 CONNECT requests

The bug

Nym exit gateways apply an exit policy (Tor format) to inbound SOCKS5 connections. The default policy, fetched from https://nymtech.net/.wellknown/network-requester/exit-policy.txt, has port-based accept rules (port 80, 22, 443, etc.) but no rules rejecting private, loopback, or link-local ranges — no equivalent to Tor's reject private:*. The network requester adds no compensating check in code: service-providers/network-requester/src/socks5/tcp.rs:33 calls TcpStream::connect(&address) immediately after the policy filter passes.

Any mixnet user can therefore have an exit gateway connect to its own 127.0.0.1, 169.254.169.254, etc., on any accept-listed port.

PoC

./nym-socks5-client init --id test --provider <gateway-provider-address>
./nym-socks5-client run --id test
curl --socks5-hostname 127.0.0.1:1080 http://169.254.169.254/

The exit gateway queries its own cloud-metadata endpoint on behalf of an anonymous mixnet user.

Scope

Every exit gateway using the default policy is vulnerable to the SSRF. To confirm it's exploitable in practice I tested 28 cloud-hosted gateways identified via whois and got cloud metadata back from 12 of them across Linode, DigitalOcean, AWS, and Vultr. Exposed data: instance IDs, internal network config, authorized SSH public keys, and account identifiers. IAM-role-bound AWS nodes would also leak short-lived STS credentials (none in my sample). Port 22 is accept-listed too, so localhost sshd is reachable from the mixnet.

Fix

Commit ad56645f ("Block non-public IPR/NR checks", #6670) added an is_global_ip() check in front of the policy filter in both the network requester and the IP packet router, with a default-off allow_local_ips flag. Shipped in nym-binaries-v2026.9-venaco. The published policy file itself still contains no private-range rejects; the fix is purely code-side, so operators must upgrade for it to apply.

Timeline

DateEvent
2026-03-31Reported to [email protected]
2026-04-15Fix committed (ad56645f), v2026.9-venaco
2026-05-08Vendor triage: Medium, $200 NYM bounty