Common Nginx Misconfigurations

Updated: Jan 10

As of March 2021, one in three websites on the internet runs on Nginx, according to a web survey by Netcraft. Nginx web server powers high-performance applications in a responsive, efficient manner and is useful for load balancing, HTTP caching, mail proxying, and reverse proxying. With the ability to handle 40,000 inactive HTTP connections with just 10Mb of

memory, it is the go-to choice for high-traffic sites.

This blog will cover the Common Nginx misconfigurations that leave your web server open to attack.

Common Nginx Misconfigurations

1. Passing Uncontrolled Requests to PHP

Most Nginx example configs for PHP advocate for passing every URI ending in .php to the PHP interpreter which could result in arbitrary code execution by third parties on most PHP setups.

In this example, all requests that the .php file extension will be passed to the FastCGI backend. A default PHP configuration is set so that it attempts to guess the file you want to execute in cases where the full path specified does not lead to a file that exists on the system. Let's say you request for /cyber/security/nginx.php, which does not exist while /cyber / security /nginx.gif actually does exist; the PHP interpreter will process /cyber / security /nginx.gif. If nginx.gif contains embedded PHP code, it will execute.

2. Alias LFI Misconfiguration

Inside the Nginx configuration look the "location" statements, if someone looks like:

There is a LFI vulnerability because:

Transforms to:

The correct configuration will be:

So, if you find some Nginx server you should check for this vulnerability. Also, you can discover it if you find that the files/directories brute force is behaving weird.

3. Missing Root Location

The root directive is positioning in your configuration matters. One of the Nginx configuration pitfalls that administrators are strongly warned against is putting the root directive inside location blocks. If you add root to every location block individually, then an unmatched location block will lack root, which would cause errors. Conversely, failure to put the root directive in a location block would give access to the root folder of the server block.

In the above example, the root folder is /etc/nginx/app meaning that files in this folder are available to us. However there is no location for / i.e location / { } but only for /cybersecurity.jpeg. As such, a request like GET ../nginx.conf would show the content of the config file etc/nginx/nginx.conf

As such, requests to / will take you to the path specified in the root directive which is globally set. The most common root paths were the following:

4. Using non-standard document root locations

Deviating from the standard root document locations laid out in the Filesystem Hierarchy Standard might seem like a fun idea sometimes. That is of course until someone requests for a file they should not be able to access and you end up getting compromised.

In the above example, a request for /etc/passwd would reveal your etc/passwd file meaning attackers would have your user list and password hashes and if your Nginx workers run as root, how your passwords have been hashed as well.

5. Unsafe variable use

Some frameworks, scripts and Nginx configurations unsafely use the variables stored by Nginx. This can lead to issues such as XSS, bypassing HttpOnly-protection, information disclosure and in some cases even RCE.


With a configuration such as the following:

The main issue will be that Nginx will send any URL to the PHP interpreter ending in .php even if the file doesn’t exist on disc. This is a common mistake in many Nginx configurations, as outlined in the “Pitfalls and Common Mistakes” document created by Nginx.

An XSS will occur if the PHP-script tries to define a base URL based on SCRIPT_NAME


Another misconfiguration related to Nginx variables is to use $uri or $document_uri instead of $request_uri. $uri and $document_uri contain the normalized URI whereas the normalization in Nginx includes URL decoding the URI. Volema found that $uri is commonly used when creating redirects in the Nginx configuration which results in a CRLF injection.

An example of a vulnerable Nginx configuration is:

The new line characters for HTTP requests are \r (Carriage Return) and \n (Line Feed). URL-encoding the new line characters results in the following representation of the characters %0d%0a. When these characters are included in a request like http://localhost/%0d%0aDetectify:%20clrf to a server with the misconfiguration, the server will respond with a new header named Detectify since the $uri variable contains the URL-decoded new line characters.

6. Raw backend response reading

With Nginx’s proxy_pass, there’s the possibility to intercept errors and HTTP headers created by the backend. This is very useful if you want to hide internal error messages and headers so they are instead handled by Nginx. Nginx will automatically serve a custom error page if the backend answers with one. But what if Nginx does not understand that it’s an HTTP response?

If a client sends an invalid HTTP request to Nginx, that request will be forwarded as-is to the backend, and the backend will answer with its raw content. Then, Nginx won’t understand the invalid HTTP response and just forward it to the client. Imagine a uWSGI application like this:

And with the following directives in Nginx:

proxy_intercept_errors will serve a custom response if the backend has a response status greater than 300. In our uWSGI application above, we will send a 500 Error which would be intercepted by Nginx.

proxy_hide_header is pretty much self explanatory; it will hide any specified HTTP header from the client.

If we send a normal GET request, Nginx will return:

But if we send an invalid HTTP request, such as:

We will get the following response: