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;
}
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
- allow_without_deny in the Gixy documentation — what the check inspects and its options
- All Gixy checks — the full list by severity
- Plugin source — the exact detection logic