ASVS 5.0 V17.1.1 requires that a TURN (Traversal Using Relays around NAT) server only allows access to IP addresses that are not reserved for special purposes. That covers internal networks, broadcast, loopback and similar ranges, for both IPv4 and IPv6. It is a Level 2 requirement.
A TURN server relays traffic for clients. If it will relay to any address the client names, it becomes a proxy into your private network.
Why it matters
A client can ask a TURN server to create a permission and send data to a chosen peer address. If that peer is 127.0.0.1, a cloud metadata address, or a host on a private subnet, the TURN server connects on the attacker's behalf from inside your perimeter. This is a server side request forgery pattern, closely related to CWE-918, with the added twist that it carries arbitrary UDP or TCP payloads.
Public TURN servers are reachable by anyone who can obtain credentials, and credentials for WebRTC apps are often handed to every visitor.
How to implement it
Deny peer addresses in the special ranges at the TURN server. For coturn, list the ranges in turnserver.conf. Cover at least these IPv4 ranges: this network (0/8), private (10/8, 172.16/12, 192.168/16), shared address space (100.64/10), loopback (127/8), link local (169.254/16, which includes cloud metadata), benchmarking (198.18/15), and multicast and reserved (224/4 and 240/4).
# turnserver.conf (check syntax against your coturn version)
no-multicast-peers
denied-peer-ip=0.0.0.0-0.255.255.255
denied-peer-ip=10.0.0.0-10.255.255.255
denied-peer-ip=100.64.0.0-100.127.255.255
denied-peer-ip=127.0.0.0-127.255.255.255
denied-peer-ip=169.254.0.0-169.254.255.255
denied-peer-ip=172.16.0.0-172.31.255.255
denied-peer-ip=192.0.0.0-192.0.0.255
denied-peer-ip=192.168.0.0-192.168.255.255
denied-peer-ip=198.18.0.0-198.19.255.255
denied-peer-ip=224.0.0.0-255.255.255.255
denied-peer-ip=::1
denied-peer-ip=fc00::-fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
denied-peer-ip=fe80::-febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff
IPv6 matters. A deny list that covers only IPv4 leaves ::1 and unique local addresses open. Also watch IPv4 mapped IPv6 forms such as ::ffff:127.0.0.1, and test them.
Add network layer defense: run the TURN server in a segment whose firewall blocks egress to internal subnets, so a config mistake does not expose them. If a specific internal peer must be allowed, add it with an explicit allow entry rather than removing a range.
How to test it
From a client with valid credentials, ask the server to relay to forbidden peers. The turnutils_uclient tool shipped with coturn can send to a chosen peer (check -h for the peer address flag in your version).
- Request a permission and send to 127.0.0.1, 10.x, 169.254.169.254, and ::1.
- Repeat with the IPv4 mapped IPv6 forms.
- Confirm the server returns an error (403 Forbidden is typical) and no packet reaches the target. Watch with tcpdump on the internal host.
- Confirm a public address still works, to prove you did not break the service.
Why the list is longer than you think
Special purpose ranges are defined in IANA registries for IPv4 and IPv6. The entries that matter for a relay are the ones that reach something other than the public internet: loopback, private use, link local, shared address space used by carriers, documentation ranges, benchmarking, multicast and the reserved block. Cloud metadata services sit on a link local address, which is why that range is high value for attackers.
IPv6 adds its own list: loopback, unique local addresses, link local, multicast, documentation prefixes, and translation prefixes that can embed an IPv4 address. Some of these forms map back to internal IPv4 targets. If your server also does NAT64 or dual stack relaying, test those paths specifically.
Authentication is not a substitute
Teams sometimes reason that only authenticated users can reach the relay, so the deny list is less important. For WebRTC that is weak, because the application usually mints TURN credentials for every visitor, often anonymously. Treat any holder of a TURN credential as untrusted, and apply the deny list regardless.
Operational advice
Keep the deny list in configuration management and review it with each coturn upgrade, because defaults and syntax have changed over time. Add a regression test to your deployment pipeline that tries a loopback relay after each release and fails the deployment if it succeeds. Log denied peer attempts, since a client probing internal addresses is worth an alert.
If you operate TURN over TCP or TLS as well as UDP, confirm that the deny rules apply to all listeners and to both allocation types. A rule that only covers UDP leaves the TCP relay path open.
Common mistakes
- Denying IPv4 private ranges and forgetting IPv6.
- Forgetting link local, which includes the cloud metadata endpoint.
- Relying on a default that changed between versions without re-testing after upgrades.
- Putting the TURN server in the same subnet as internal databases.
A quick audit script
An inexpensive regression check is a script that, after each deployment, requests allocations and relay permissions for a fixed list of forbidden peers: loopback, a private address, the link local metadata address, and their IPv6 counterparts. It should expect an error for every one and a success for a public test address. Run it from outside your network with a normal user credential, so it exercises the same path an attacker would. If any forbidden peer succeeds, fail the release.
Pair that with periodic external scanning of the TURN ports to confirm only the intended listeners are open, and with a review of which hosts the TURN subnet can reach.
Quick check
Is blocking 10.0.0.0/8 enough?
No. Loopback, link local, shared address space, multicast, and all the IPv6 equivalents also need to be denied.
Where is the second line of defense?
Egress firewall rules around the TURN host, so internal networks are unreachable even if the application config is wrong.