hack

Nginx Misconfiguration

Examples of nginx misconfigurations that can expose sensitive data, complete with a Docker Compose lab to reproduce them

Source: haova/nginx-misconfig

Environment

To set up the environment and run the following examples, use Docker Compose:

cd <repo-dir>
docker compose up

To stop, press Ctrl+C or run:

docker compose down

Problems

Alias Traversal

alias defines a replacement for the specified location. However, if you configure a location without a trailing / while the alias value ends with /, an attacker can traverse to parent directories.

For example:

location /public {
    alias /usr/share/nginx/public/;
}

When you request http://localhost:8080/public/content.txt, nginx replaces the /public part with /usr/share/nginx/public/, so the resolved file path is /usr/share/nginx/public//content.txt.

By using .. (parent directory traversal), the attacker can access parent directories via http://localhost:8080/public../secret.txt, which resolves to /usr/share/nginx/public/../secret.txt.

If the location is corrected to /public/, the attacker can no longer access http://localhost:8080/public../secret.txt because it does not match the location. If the attacker instead uses http://localhost:8080/public/../secret.txt, nginx normalizes the .. in the path to /secret.txt before location matching, so the request no longer matches the /public/ location and the traversal fails.

Test commands:

# public content
curl localhost:8080/public/content.txt

# secret content
curl localhost:8080/public../secret.txt

Absolute Redirect

In nginx, absolute_redirect is on by default. When a redirect is triggered, nginx always builds an absolute redirect URL in the format Location: [scheme]://[server_name]:[port][request_uri].

This can reveal sensitive information, such as the original IP/port.

For example, with alias, nginx redirects a location without a trailing slash to the URL ending with a slash (localhost:8080/public -> localhost:8080/public/). Combined with absolute_redirect, the server's origin is disclosed.

curl -i localhost:8080/public

Output:

HTTP/1.1 301 Moved Permanently
Server: nginx/1.31.4
Date: Sun, 23 Aug 2026 15:09:11 GMT
Content-Type: text/html
Content-Length: 169
Location: http://localhost:8080/public/
Connection: keep-alive

This is dangerous when the server is behind a WAF/proxy such as Cloudflare.

Scan

To detect problems in your web, you can use nuclei.

nuclei -u localhost:8080 -no-interactsh -tags nginx,misconfig,traversal