stub_status is reachable by anyone

stub_status hands out live connection counts and request rates to whoever asks. It is monitoring data, and it is reconnaissance data.

MEDIUM status_page_exposed 4 min read Updated: August 2026

What Gixy reports

[status_page_exposed] stub_status is publicly accessible without IP restrictions.
  Severity: MEDIUM
  Reason: no allow directives found; no "deny all" found

What leaks

The endpoint is small. That does not make it harmless:

Active connections: 291
server accepts handled requests
 16630948 16630948 31070465
Reading: 6 Writing: 179 Waiting: 106

From those seven numbers an attacker learns:

  • Your traffic volume -- request totals over two samples give a precise rate.
  • Your capacity headroom -- active connections against your published worker_connections shows how much load it would take to exhaust you.
  • Whether an attack is working -- a live feedback channel during a denial-of-service attempt, which is the genuinely dangerous one. Polling this endpoint tells them when to stop scaling up.
  • Your deployment rhythm -- accepts and handled diverging, or counters resetting, marks reloads and restarts.

The mistake

server {
    listen 443 ssl;
    server_name example.com;

    location /nginx_status {
        stub_status;
    }
}

Obscurity is not a fix. /nginx_status, /status, /stub_status and /basic_status are in every scanner's wordlist, and an unusual path is one directory-brute-force away.

The fix

Restrict by address, and close the list with deny all;:

server {
    listen 443 ssl;
    server_name example.com;

    location /nginx_status {
        stub_status;

        allow 127.0.0.1;
        allow 10.0.0.0/8;      # monitoring subnet
        deny all;

        access_log off;
    }
}

Gixy wants to see both an allow and a deny all; in the same scope. An allow on its own leaves the list open at the bottom -- the allow_without_deny problem.

Better: keep it off the public listener entirely

Address filtering is one misconfigured real_ip setting away from failing open. A listener that is not reachable from the network at all has no such failure mode. A Unix socket is the strongest version of this, and Gixy explicitly exempts a server block whose every listen is a Unix socket:

server {
    listen unix:/var/run/nginx-status.sock;
    server_name localhost;

    location /nginx_status {
        stub_status;
        access_log off;
    }
}

Point your monitoring agent at the socket and nothing traverses the network. Most agents support this; curl --unix-socket /var/run/nginx-status.sock http://localhost/nginx_status confirms it by hand.

A loopback TCP listener is still flagged. listen 127.0.0.1:8080; is genuinely unreachable from outside, but Gixy's exemption covers Unix sockets only, so it will still report the check. That is a real false positive — either switch to a socket as above, or keep allow 127.0.0.1; deny all; in the location so the finding clears on its own terms.

Behind a CDN or load balancer, allow lists see the proxy

If your allow list contains the address of your own load balancer, every request through it matches -- including the attacker's. Configure set_real_ip_from and real_ip_header so the rules evaluate the true client, or use the localhost listener above.

Verify the fix

gixy /etc/nginx/nginx.conf

# From outside -- the only test that counts:
curl -sS -o /dev/null -w '%{http_code}\n' https://example.com/nginx_status
# expect 403

# From the monitoring host:
curl -sS https://example.com/nginx_status
# expect the counters

When this is a false positive

When the enforcement is real but lives outside this config -- a firewall rule, a security group, or a listener on an interface that is not routable from the internet. Gixy reads the config file and cannot see any of those. The finding is still worth keeping honest: confirm the external control actually exists rather than assuming it does, because "it is on an internal network" is the assumption that gets audited most often and holds least often.

Reference