Apache mod_status /server-status Information Disclosure means anyone who can reach your web server can open the /server-status page and see live requests, client IP addresses, virtual hosts and worker load. Fix it by disabling mod_status if you do not use it, or by wrapping the handler in a Require local (or admin network) rule, then reloading Apache.
What the scanner is actually detecting
This is a remote, unauthenticated check. On each port where Nessus has already identified Apache httpd, it requests /server-status and flags the port when the Apache status page comes back instead of a 403 or 404. It never reads your configuration files, so a restriction that exists on disk but does not apply to the virtual host that answered still produces a hit.
| Scanner | Finding title | ID and rating |
|---|---|---|
| Nessus (Tenable) | Apache mod_status /server-status Information Disclosure | Plugin 10677, family Web Servers, Medium (CVSS v3 5.3) |
Tenable’s solution text is short: disable mod_status or restrict access to specific hosts. The Nmap script http-apache-server-status requests the same URL, so you can reproduce the result without Nessus.
How serious is it?
An Apache server-status information disclosure does not give anyone code execution or a shell. It is rated Medium because it hands out reconnaissance data without authentication or an exploit. The Apache documentation lists what the page shows: worker counts and states, uptime, request and byte rates, CPU usage and, when ExtendedStatus is on, the client and request each worker is currently serving. Since httpd 2.3.6, loading mod_status switches ExtendedStatus on by default, so most exposed pages include the full per-request table.
In practice that means:
- URLs in flight, including query strings. Applications that put tokens, session IDs or reset codes in URLs leak them here.
- Client IP addresses of other visitors, which is a privacy problem on its own.
- Virtual host names, including internal or staging names that are not in public DNS.
- Apache version and uptime, which hint at how long ago the service was last restarted or patched.
On Debian and Ubuntu the packaged status.conf also turns on ProxyStatus when mod_proxy is loaded, which adds load balancer details to the page. Exposure to the internet matters far more than exposure on an internal admin segment. If you are not sure which hosts are reachable from outside, start by defining your external attack surface management scope.
How to confirm it on the host
From a machine that is not the web server, ideally on the network the scanner used:
curl -i http://www.example.com/server-status
curl -i "http://www.example.com/server-status?auto"
curl -ik https://www.example.com/server-status
curl -i -H "Host: intranet.example.com" http://203.0.113.10/server-status
nmap -p 80,443 --script http-apache-server-status www.example.com
An exposed server returns 200 with a page headed “Apache Server Status for” the host name, or plain key: value lines for ?auto. A fixed server returns 403 (restricted) or 404 (no handler). The Host header test matters because each virtual host can carry its own rules.
On the server, check whether the module is loaded and where the handler is mapped:
# Is mod_status loaded?
sudo apachectl -M | grep status_module # RHEL, Rocky, AlmaLinux
sudo apache2ctl -M | grep status_module # Debian, Ubuntu
# Where is the handler configured?
sudo grep -Rni 'server-status' /etc/httpd/ /etc/apache2/ 2>/dev/null
sudo grep -Rn --include=.htaccess 'server-status' /var/www/ 2>/dev/null
# Which virtual host answers which name and port?
sudo apachectl -S
The .htaccess search is deliberate: the mod_status documentation warns that once the module is loaded, its handler is available in all configuration files, including per-directory files.
Know your defaults. Debian and Ubuntu enable mod_status on install and ship /etc/apache2/mods-available/status.conf with Require local. The RHEL family loads the module from /etc/httpd/conf.modules.d/00-base.conf but maps no /server-status URL in the default httpd.conf. On either family, a hit usually means someone added or loosened a rule, a virtual host overrides it, or a proxy sits in front (all covered below).
How to fix it
Option 1: disable mod_status if nothing uses it
First check whether a monitoring agent or exporter reads /server-status?auto. If one does, use option 2 instead.
Debian and Ubuntu (this removes both the status.load and status.conf symlinks from mods-enabled):
sudo a2dismod status
sudo apache2ctl configtest && sudo systemctl restart apache2
RHEL, Rocky and AlmaLinux, by commenting out the LoadModule line:
sudo cp -a /etc/httpd/conf.modules.d/00-base.conf /root/00-base.conf.bak
sudo sed -i 's/^LoadModule status_module/#LoadModule status_module/' /etc/httpd/conf.modules.d/00-base.conf
sudo apachectl configtest && sudo systemctl restart httpd
Also remove any SetHandler server-status blocks you found, so the configuration does not rely on the module staying absent, and re-check the file after httpd package updates.
Option 2: keep it for localhost or an admin network only
On Debian and Ubuntu, edit /etc/apache2/mods-available/status.conf, which already contains this block. On the RHEL family, create /etc/httpd/conf.d/status.conf:
<Location "/server-status">
SetHandler server-status
Require local
# Require ip 192.0.2.0/24
</Location>
Require local matches 127.0.0.0/8, ::1, and any connection where the client and server addresses are the same, so an agent on the box keeps working. If a central monitoring server polls remotely, add a Require ip line with its address or subnet rather than opening the page to everyone. Never use Require all granted here, and do not mix 2.2 style Order, Allow and Deny directives with Require; Apache’s upgrade guide shows that mixing them produces results you did not intend.
sudo apachectl configtest && sudo systemctl reload httpd # RHEL family
sudo apache2ctl configtest && sudo systemctl reload apache2 # Debian family
Check for a virtual host that overrides the rule
Apache merges <Location> sections in the order they appear, and sections inside a <VirtualHost> are applied after those outside it. With AuthMerging at its default of Off, a later section’s authorization directives replace the inherited ones. So a virtual host containing <Location "/"> with Require all granted, which is common in reverse proxy configs, quietly reopens /server-status for that site. Repeat the server-status block inside that virtual host, after the <Location "/"> block.
Behind a reverse proxy on the same host
If nginx, HAProxy, Varnish or a tunnel agent on the same machine forwards traffic to Apache over 127.0.0.1, every request reaches Apache from a local address and Require local lets the whole internet in. The mod_authz_host documentation warns that behind a proxy the client address is the proxy’s address. Deny the path at the proxy, for example in each nginx server block:
location /server-status {
deny all;
}
Alternatively, mod_remoteip can replace the client address with the one from X-Forwarded-For so that Require ip evaluates the real client. Only trust that header from proxies you control.
Turn ExtendedStatus off if you only need basic counters
Set ExtendedStatus Off at server config level (on Debian, change the line in status.conf). It cannot be set per virtual host and cannot be changed by a graceful restart, so do a full restart. Per the mod_status documentation, this also removes access totals, averages and CPU figures, so check what your dashboards graph first.
Source builds and Windows packages
The upstream layout keeps the status handler in conf/extra/httpd-info.conf, loaded by an Include line that is commented out in the stock httpd.conf. If that line is active, replace the sample Require host .example.com with your own admin rule. The same file maps /server-info, which deserves the same restriction.
How to verify the fix and rescan
- Repeat the remote curl tests against every hostname, IP and port in the finding, including each name-based virtual host via the Host header. Expect 403 or 404.
- Test the path the scanner used: if it scanned a public VIP or CDN name, test that, not only the backend node.
- Confirm local monitoring still works:
curl -s "http://localhost/server-status?auto" | head. If Apache does not listen on loopback, use the server’s own IP. - Rescan from the same scanner location, with the original policy or one limited to plugin 10677 on the affected hosts.
What can break and how to roll back
Nothing user-facing depends on /server-status. Disabling the module breaks whatever reads the page: monitoring agents, exporters, capacity dashboards and the balancer view added by ProxyStatus. Restricting it breaks only remote pollers, which get 403 until you add their address. Turning ExtendedStatus off removes per-request data and totals that some graphs rely on. Back up every file before editing. To roll back:
- Debian and Ubuntu:
sudo a2enmod status, then restart apache2. - RHEL family: restore
/root/00-base.conf.bakand restart httpd. - Access rules: restore the previous file, run configtest and reload.
- nginx: remove the
locationblock, runnginx -tand reload.
Common false positive reasons
- Scanner inside the allowed range. If the scanner sits in the admin subnet you allowed with
Require ip, it sees the page. Access is restricted; record the evidence, or confirm from a normal network segment. - Different Apache instance. The page came from a front-end Apache proxy, or a second instance on another port bundled with an application or control panel, not the one you changed.
- Catch-all response. Read the plugin output. If it shows a generic application page rather than status content, the path is not really exposed.
- Stale results. The report predates the change, or a node was out of the pool when you tested.
One case looks like a false positive but is not: Require local behind a same-host proxy. If the remote curl test shows the page, the finding is real.
FAQ
Is Require local enough?
Yes, when clients connect straight to Apache. No, when a proxy on the same host forwards traffic, because every request then looks local.
Does 403 or 404 matter for the scan?
Either closes the finding. A Require rule gives 403 and disabling the module gives 404. The only difference is that 403 confirms the path exists.
Does hiding the Apache version with ServerTokens fix it?
No. The page is still served. Only disabling the handler or restricting access removes the exposure.
Does this cover /server-info too?
No. /server-info comes from mod_info and is reported as a separate finding, but it exposes your configuration and should be restricted or disabled the same way.
Tracking this finding across many hosts
This check fires per host and per web port, so a large Apache estate can produce many near-identical rows. SITEY, a self-hosted vulnerability management platform, imports findings from 16 scanners (Nessus results arrive as an uploaded .nessus export) and merges duplicates within each scanner. Plugin 10677 findings can be re-tested individually after the change, and AI-drafted, host-specific fix scripts run through agents on Linux endpoints only after a human approves them.
Sources
- Tenable: Apache mod_status /server-status Information Disclosure (plugin 10677)
- Apache HTTP Server 2.4 documentation: mod_status
- Apache HTTP Server 2.4 documentation: ExtendedStatus directive
- Apache HTTP Server 2.4 documentation: mod_authz_host (Require local, Require ip)
- Apache HTTP Server 2.4 documentation: Configuration sections and merging