allow without deny restricts nothing

An allow list with no deny all; at the end is not a restriction. It is a comment that happens to be valid syntax.

HIGH allow_without_deny 4 min read Updated: August 2026

What Gixy reports

[allow_without_deny] Found allow directive(s) without deny in the same context.
  Severity: HIGH
  Reason: You probably want "deny all;" after all the "allow" directives

The mistake

ngx_http_access_module evaluates its rules in order and stops at the first match. If nothing matches, access is granted. So a block that lists who is allowed, without ever saying what happens to everyone else, permits everyone else.

location /admin/ {
    allow 10.0.0.0/8;
    allow 192.168.1.0/24;

    proxy_pass http://admin_backend;
}

A request from 203.0.113.9 matches neither rule, falls off the end of the list, and is served. The two allow lines changed nothing. The intent is obvious to a human reading it and invisible to nginx.

The fix

Close the list. deny all; goes last, after every allow:

location /admin/ {
    allow 10.0.0.0/8;
    allow 192.168.1.0/24;
    deny all;

    proxy_pass http://admin_backend;
}
Order matters. Rules are checked top to bottom and the first match wins. deny all; placed first would reject everything, including the addresses you just allowed.

Watch the inheritance

Access rules are inherited from an outer context only when the inner context defines none of its own. A single allow in a location discards the entire server-level rule set for that location -- including its deny all;. This is the subtle version of the same bug:

server {
    allow 10.0.0.0/8;
    deny all;              # server-wide restriction

    location /metrics/ {
        allow 172.16.0.1;  # replaces the whole set above -- /metrics/ is now public
        stub_status;
    }
}
server {
    allow 10.0.0.0/8;
    deny all;

    location /metrics/ {
        allow 172.16.0.1;
        allow 10.0.0.0/8;
        deny all;          # restate it -- inheritance does not apply here
        stub_status;
    }
}

Verify the fix

gixy /etc/nginx/nginx.conf

# From an address that should be refused:
curl -sS -o /dev/null -w '%{http_code}\n' https://example.com/admin/
# expect 403

# From an allowed address:
curl -sS -o /dev/null -w '%{http_code}\n' https://example.com/admin/
# expect 200

Test from outside your network, not from the server itself. A curl run on the box originates from 127.0.0.1, which your allow list very likely permits, and will pass whether the config is right or wrong.

When this is a false positive

Gixy already exempts the common intentional case: a bare allow all;, which is how you deliberately re-open a nested location inside an otherwise restricted parent. It is not flagged.

The genuine false positive is defence in depth by layer -- an allow list here that is only a second gate, with the real enforcement in a firewall, a service mesh, or an upstream application. That is a reasonable design, but the nginx layer still is not restricting anything, so treat the finding as documentation of where your actual boundary lives rather than as noise.

allow/deny is address-based only

These rules see the connecting peer's address. Behind a CDN or load balancer that is your proxy, not your visitor, so an allow list will match every request or none. Configure set_real_ip_from and real_ip_header first, or do the check somewhere that sees the real client.

Reference