Review the source, run the exact configuration through the target Nginx build, and test representative requests. A warning is a prompt to investigate context—not proof that a configuration is exploitable.
1. Make request routing explicit
- Confirm the intended default server for every listening address and port.
- Review exact, prefix,
^~, and regex locations together—not one block in isolation. - Test paths immediately above and below the changed prefix.
- Trace internal redirects caused by
try_files,error_page, and rewrites.
Nginx first remembers the longest prefix location, then evaluates regular-expression locations in source order unless ^~ suppresses that phase. An exact = match stops the search. The official location documentation is the source of truth; test concrete URIs whenever a change can alter precedence.
2. Bound proxy destinations and preserve deliberate identity
- Avoid constructing unrestricted upstream destinations from user-controlled hostnames or URIs.
- Set the upstream
Hostheader deliberately instead of inheriting an accidental value. - Review
proxy_passURI behavior when the surrounding location or rewrite changes. - Set connect, send, and read timeouts to match the endpoint rather than relying on unexplained defaults.
- Verify certificate name and trust settings for HTTPS upstreams.
A syntactically valid variable-based proxy_pass can still create an open-proxy or server-side request forgery path. Prefer a fixed upstream or an allowlisted mapping, then test destinations that must be rejected.
3. Treat forwarded and response headers as policy
- Overwrite trusted forwarding headers at the edge; do not blindly pass client-supplied values.
- Define which proxy is allowed to establish the real client IP.
- Do not combine wildcard CORS origins with credentialed requests.
- Use
alwayswhere a security header must also appear on error responses. - Keep header values free of unvalidated variables that can introduce response splitting.
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;These lines are a common starting point, not a universal answer. The correct trust boundary depends on whether another load balancer or CDN sits in front of Nginx.
4. Check the TLS configuration as a deployed system
- Enable only protocol versions supported by your compatibility policy.
- Confirm the certificate chain, private-key access, names, and renewal path.
- Review HTTP-to-HTTPS redirects for every hostname, including unknown hosts.
- Add HSTS only after HTTPS works reliably across the intended scope.
- Test the public endpoint after deployment; a local file review cannot see the whole TLS path.
Avoid copying an old cipher list without understanding who owns it. Nginx, the linked TLS library, a fronting proxy, and your client support policy all affect the effective result.
5. Make access-control ordering auditable
- Put administrative, diagnostic, and internal endpoints behind explicit controls.
- Review
allowanddenyrules in order. - Check whether a nested location replaces inherited rules.
- Protect files such as dotfiles, backups, keys, and unprocessed source artifacts.
- Test both an allowed and a denied request from realistic network positions.
The Nginx access module documentation states that address rules are checked in sequence until the first match. That makes ordering part of the policy, not just formatting.
6. Put a budget on regular expressions and rewrite loops
- Prefer prefix or exact locations where a regex is not necessary.
- Review nested quantifiers and ambiguous repetition in patterns influenced by request data.
- Anchor server-name and location expressions when partial matching is not intended.
- Trace
rewrite ... lastback through location selection. - Load-test suspicious patterns with bounded, non-production inputs.
Nginx limits internal redirect cycles, but reaching that limit still produces a failed request. The rewrite module documentation explains how a last rewrite starts a new location search and why some loops need break instead.
Turn the checklist into a release gate
- Keep configuration in version control and review the complete rendered diff.
- Run editor inspections for fast structural and security feedback.
- Run
nginx -tor-Twith the deployment-shaped build and files. - Send positive and negative requests through a local or staging instance.
- Roll out gradually, monitor errors and latency, and retain the previous known-good artifact.
Static analysis cannot know every intended trust boundary, upstream behavior, or environment-specific invariant. Suppress a finding only after documenting why the actual configuration is safe, and keep the runtime tests that protect that reasoning.