Safeguard
Application Security•

ASVS 5.0 V13.2.4: Allowlist Where Your Application Can Connect

ASVS 5.0 V13.2.4 (Level 2): define an allowlist of external systems the app may contact. Code for SSRF safe fetching plus network egress rules.

Safeguard Security Team
3 min read

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

  1. 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.
  2. 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.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.