ASVS 5.0 V13.2.4 requires an allowlist that defines the external resources or systems your application may talk to, for outbound requests, data loads or file access. It can live in application code, the web server, a firewall or several layers together. It is Level 2.
Deny by default. If a destination is not on the list, the connection does not happen.
Why it matters
Server side request forgery turns your server into a proxy for an attacker: they make it fetch the cloud metadata endpoint, an internal admin page or a database port. An egress allowlist also limits what malware or a compromised dependency can reach and where data can be exfiltrated.
How to implement it
Use two layers. The application checks every user influenced destination, and the network blocks everything else.
Application layer, in Python:
import ipaddress, socket
from urllib.parse import urlparse
ALLOWED_HOSTS = {"api.partner.example", "files.partner.example"}
def check_url(url: str) -> str:
u = urlparse(url)
if u.scheme != "https" or u.hostname not in ALLOWED_HOSTS:
raise ValueError("destination not allowed")
for info in socket.getaddrinfo(u.hostname, 443, proto=socket.IPPROTO_TCP):
ip = ipaddress.ip_address(info[4][0])
if not ip.is_global:
raise ValueError("resolves to non public address")
return url
When you then fetch, disable redirects or re-check each hop, and connect to the address you validated to avoid DNS rebinding.
Network layer, a Kubernetes egress policy:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: orders-egress
namespace: prod
spec:
podSelector:
matchLabels:
app: orders
policyTypes: ["Egress"]
egress:
- to:
- ipBlock:
cidr: 203.0.113.0/24
ports:
- protocol: TCP
port: 443
Keep the list tied to the document from V13.1.1.
How to test it
- Submit URLs for http://169.254.169.254/, http://localhost:8080/, a hostname that resolves to a private IP and an allowed host with a redirect to a disallowed one. All must be refused.
- From the running pod, try to reach an arbitrary public host:
kubectl exec -n prod deploy/orders -- wget -T 3 -qO- https://example.org
It must time out or be denied.
Click through it at your own pace, or open it full screen.
Common mistakes
- A blocklist of bad addresses instead of an allowlist.
- Checking the hostname string but not the resolved address.
- Following redirects blindly.
- Allowing a whole cloud provider range because "our partner is hosted there".
Try it yourself
Start in report mode. Add logging to your outbound HTTP client wrapper that records the destination host for every call, run it in staging for a week of normal traffic and collect the unique hosts. That list is the first draft of your allowlist and a useful input for V13.1.1.
Review it with the owners. Anything surprising deserves a question: telemetry, an unused SDK, a feature that was supposed to be removed. Then switch the wrapper from logging to enforcing, with a clear error, and add the network egress policy as a second layer.
Keep one test that tries the cloud metadata address and a private range, so the protection cannot be removed unnoticed.
Quick check
Is application level validation enough on its own?
Better to have both. The network layer still protects you when code has a bug or a dependency makes its own calls.