Skip to content

[ssrf] Server Side Request Forgery

What this check looks for

This plugin looks for proxy_pass usage where the upstream address is built from variables that can be influenced by the client (scheme, host, port, or path). That is the classic NGINX SSRF shape.

Why this is a problem

If an attacker can control where NGINX sends a request, they can:

  • scan internal networks,
  • reach metadata services,
  • hit admin panels that are not exposed publicly,
  • and in some cases pivot into more serious compromises.

This is especially dangerous when the proxy location is intended to be "internal" but can be reached via rewrites, error_page, try_files, or other internal redirects.

Bad configuration

location ~* ^/internal-proxy/(?<proxy_proto>https?)/(?<proxy_host>.*?)/(?<proxy_path>.*)$ {
    internal;

    proxy_pass $proxy_proto://$proxy_host/$proxy_path;
    proxy_set_header Host $proxy_host;
}

Marking a location internal helps, but it does not automatically make the whole setup safe if other directives can route a request into it.

A common mistake is combining an unsafe rewrite with the internal proxy:

rewrite ^/(.*)/some$ /$1/ last;

location ~* ^/internal-proxy/(?<proxy_proto>https?)/(?<proxy_host>.*?)/(?<proxy_path>.*)$ {
    internal;
    proxy_pass $proxy_proto://$proxy_host/$proxy_path;
}

Better configuration

If the set of upstream hosts is small, hardcode them and select with a map:

map $arg_target $upstream_host {
    default "";
    one "backend1.internal";
    two "backend2.internal";
}

server {
    location /proxy/ {
        if ($upstream_host = "") { return 400; }

        proxy_pass http://$upstream_host;
        proxy_set_header Host $upstream_host;
    }
}

If you cannot enumerate hosts, treat the upstream address as a signed token (HMAC) rather than raw client input, and verify it before proxying.

Additional notes

Variable-based proxying is not inherently insecure, but the moment the variable is derived from user input, you need a tight allowlist and a plan for internal redirect paths (rewrite, error_page, try_files, X-Accel-Redirect, and subrequests).