[ssrf] Server Side Request Forgery
What this check looks for
This plugin looks for proxy_pass, fastcgi_pass, uwsgi_pass, scgi_pass, or grpc_pass usage where the upstream address is built from variables that can be influenced by the client (host, port, and — for proxy_pass/grpc_pass — the scheme 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).