July 2, 2026
  •  
9
 Min 
Read

What /server-status is

Apache's mod_status module ships with the server. When enabled, it exposes a live dashboard at the URL /server-status that shows what the server is doing right now: every request currently being processed, the URL of that request (including query string), the client's IP address, the virtual host it hit, the worker's state, how long it's been running. The page is regenerated on every request — pull it every second, and you have a rolling transcript of the server's traffic.

The dashboard is meant for the server operator to check in from localhost. The Apache docs' example config restricts access to a specific host precisely because the page is not intended for the public. When that restriction goes missing, the dashboard becomes a live public feed of the site's traffic, readable by anyone on the internet.

That's the misconfiguration this blog is about, and it's the one Sucuri wrote up in 2012.

The 2012 baseline

In October 2012, Sucuri crawled about 10 million websites and found that "hundreds" of them were serving their Apache /server-status page publicly. Their write-up named 13 big brands in particular: PHP.net, Apache.org, Cisco.com, Ford.com, NBA.com, Staples, latimes.com, Chicago Tribune, Metacafe, disney.go.com, cloudflare.com, TweetDeck, and yellow.com.

That list is a cross-section of the 2012 web. News, sports, government-adjacent tech vendors, e-commerce, Disney. Sucuri's point at the time was simple: the mistake is not exotic, and it lands on brand names you would recognize. They also stopped short of publishing a headline number — "hundreds" was as precise as it got — which is what left me curious enough to re-run the measurement nearly fourteen years later.

What I actually did

Two-step scan against the CRUX Top 1M — Chrome's real-user visits dataset, and the closest current-day equivalent to the Alexa Top 1M that was the standard corpus in 2012.

  • Send GET /server-status at every hostname on the list.
  • For every 200 OK response, validate the body by requiring that <title>Apache Status</title> is present. Anything short of that gets rejected.

Only the confirmed hits go into the numbers below.

Signature validation is not optional. Plenty of sites respond 200 OK to /server-status with an SPA catch-all, a WAF challenge page, or a custom error handler — count those, and you overstate the problem by 70x.

Disclaimer: I do not collect or analyze any of the data beyond the aggregated numbers mentioned in this publication.

It uses webcensus, my Rust internet-wide reconnaissance framework, as the scanner.

Numbers

The probe funnel: 985,763 GET /server-status requests went out, one per hostname on the CRUX Top 1M. 858,852 hosts were reachable. 82,969 of them returned HTTP 200 OK on the path. 75,890 of those had bodies worth saving. 1,149 passed signature validation.

For the 2012 revisit, I checked every one of the 13 named sites — both by direct probe and by looking for their hostnames in the confirmed set.

Zero of the 13 sites Sucuri named in 2012 still leak /server-status in 2026.

Some had mod_status disabled entirely (Apache.org, Cisco.com, Ford.com, NBA.com, disney.go.com, latimes.com). Some now sit behind a CDN that returns 403 on the path (Chicago Tribune). Three are defunct as businesses (Metacafe, TweetDeck, yellow.com). Two — PHP.net and Staples — didn't make the top 1M and weren't probed at all, but a direct check today shows both return 404 on /server-status.

The named list has been cleaned up over the years. What that says about the wider ecosystem is a separate question — the count I actually have is 1,149 exposed hosts in the CRUX Top 1M today, and none of them are among the 13 names Sucuri picked in 2012.

The 1,149

The full CRUX Top 1M gives us 1,149 confirmed hosts leaking /server-status in July 2026, spread across 981 unique organizations after grouping subdomains under their parent domain.

90.6% of affected organizations leak exactly one hostname. Thousands of independent teams making the same mistake. The exposure is not concentrated at a handful of large operators; it is scattered across thousands of small, unrelated sites.

Software versions still in the wild

Across the 1,149 confirmed hits, 1,018 run some Apache 2.4.x release and 115 are still on the 2.2.x branch. Apache 2.2 has been end-of-life since July 2018. Roughly one in ten hosts leaking /server-status today is running a version that stopped receiving security updates eight years ago.

One host runs Apache 2.0, which reached end-of-life in 2013. The remaining fifteen hits are not vanilla httpd at all: six run IBM_HTTP_Server (IBM's Apache-derived commercial webserver), five run Oracle-HTTP-Server, and four report just Apache with the version scrubbed by ServerTokens Prod. Enterprise Apache derivatives inherit mod_status and are just as susceptible to this misconfiguration — the story is not narrowly about open-source Apache.

Some of the specific banners visible in the response headers of the Apache hosts:

  • 37 hosts advertise OpenSSL/1.0.1e — the Heartbleed-era release. It is very likely back-patched by the distribution vendor, but the version they report hasn't changed since 2013.
  • 21 hosts advertise PHP/5.3.3, and 9 more advertise PHP/5.2.17. Both branches have been unsupported for over a decade.
  • 15 hosts run Apache/2.2.3 (Red Hat) — the default httpd that shipped with RHEL 5.

Cloudflare in the middle

Of the 1,149 confirmed leaks, 348 (about 30%) resolve to an IP address inside Cloudflare's published IPv4 ranges. The client connects to a Cloudflare edge, Cloudflare fetches from the origin, and the origin's Apache serves /server-status straight through.

I want to be careful with this claim. Cloudflare offers a large and evolving set of managed rules across their plans, and I did not test every combination. What I can say is: for the 348 sites in this dataset, whatever policy their operator had in place did not stop the leak.

What ends up on the page

Of the 1,149 confirmed hits, 1,125 (97.9%) had ExtendedStatus on — meaning the page includes a per-request table with URL, virtual host, client IP, protocol, and worker state for every connection Apache is currently handling.

The default for ExtendedStatus changed with Apache 2.3.6 (2010): once mod_status loads, ExtendedStatus is on unless explicitly turned off. That default cascaded. Practically every server that exposes /server-status today also exposes the request table.

Aggregate stats across the 1,125 ExtendedStatus pages, measured at the moment of my one probe:

  • 1,125 pages (100%) had at least one other user's request URL visible in the table at the moment of my probe.
  • 636 pages (56.5%) exposed a non-loopback client IP address of a real visitor.
  • 50 pages (4.4%) had at least one visible URL matching a token / JWT heuristic — query strings containing ?token=, ?apikey=, ?access_token=, ?session=, or a base64 eyJ... fragment.
  • 3,430 distinct virtual hosts were observable across the pages — meaning many of these Apaches also host neighboring sites whose traffic patterns are visible to anyone who reads /server-status.

That last number is the shared-hosting spillover. One misconfigured Apache on a shared box exposes the traffic of every tenant vhost on the same server. In this dataset, one single IP address (a cPanel-style shared host) is responsible for 15 leaking hostnames at once. Fix one config file, close 15 leaks.

Each of those pages can be pulled on a loop by anyone. My probe is one snapshot; the same URL fetched every second reconstructs a rolling transcript of every request the server is handling. Tools that do this have existed since at least 2017 — the reference implementation is server-status_PWN.

Why the tokens-in-URL number is a floor

The 50 pages with token-shaped query strings is measured only on request URLs I could see in one snapshot. A live watcher pulling /server-status every second for 24 hours would see everything that came through in that window.

Tokens that pass through URL parameters are a design mistake, and modern frameworks default against it. But every dataset like this shows that "should not" and "does not" are different things. Legacy admin panels, embedded devices, older CMS versions, download-link systems, password-reset flows — all of these still ship secrets in query strings, and every one of them ends up in the request table if the operator has mod_status open.

TLS does not help with this. The site owner is the one publishing the traffic.

Threat model

This exposure gives an unauthenticated observer:

  • The URLs of other users' active requests to your site — every path, every query string parameter.
  • The client IP address of every visitor connecting at that moment.
  • The virtual host names hosted on the server, revealing shared-tenancy layouts and internal-looking subdomains.
  • The versions of Apache, OpenSSL, PHP, and other modules on the server.
  • The scoreboard states of every worker, from which request rate and traffic patterns can be inferred.

For a single site, it's a slow leak useful to an attacker. Across all 1,149, it's live web traffic anyone can sit and watch.

Reproduce it in 60 seconds

To make what this actually looks like concrete, I put a minimal reproducer on GitHub at Kirill89/server-status-60-second-demo. Three files: a Dockerfile, one Apache config, one PHP file. They spin up a vulnerable server plus a background loop that fakes a stream of "user logins" with tokens in the query string.

docker build -t server-status-demo https://github.com/Kirill89/server-status-60-second-demo.git
docker run --rm -p 8080:80 server-status-demo

From another terminal:

curl -s http://localhost:8080/server-status

You get a full HTML /server-status page. The interesting part is the request table:

Or, more directly:

Srv  PID    Acc   M  CPU  SS  Req  Conn  Child  Slot  Client     Protocol  VHost         Request
0-0  8      1/6   W  0.00 0   0    0.0   0.00   0.00  127.0.0.1  http/1.1  localhost:80  GET /?token=eyJhbGciOiJIUzI1NiJ9.LEAKED_a3f19c8b HTTP/1.1
1-0  9      1/6   W  0.00 0   0    0.0   0.00   0.00  127.0.0.1  http/1.1  localhost:80  GET /?apikey=sk_live_a3f19c8b7d0e14f2a5 HTTP/1.1
2-0  10     1/6   .  0.00 1   0    0.0   0.00   0.00  127.0.0.1  http/1.1  localhost:80  GET /?token=eyJhbGciOiJIUzI1NiJ9.LEAKED_b8e720c3 HTTP/1.1
curl -s http://localhost:8080/server-status | grep -oE '(token|apikey)=[a-zA-Z0-9._]+'

Every second you get a new pair. Poll for an hour, and you have thousands of "user session tokens" — every one of them ripped straight from a URL the app never intended to publish.

The whole misconfiguration is this, in the Apache config:

<Location "/server-status">
  SetHandler server-status
</Location>

No CVE. No exploit code. The server does exactly what it was told to do.

Fix

Two lines in the Apache config file, and it's over:

<Location "/server-status">    
  Require local
</Location>

Or delete the <Location> block entirely if you don't need it. On systems where mod_status is loaded but there is no matching <Location> block, it serves nothing.

If you cannot fix the origin — because it's a legacy box, a hosting-provider default, or something you don't own — block the path at the edge:

if ($uri ~* ^/server-(status|info)){    
	return 404;
}

Nginx, HAProxy, and every CDN's WAF let you do the same thing in one line. It's not a permanent fix, but it stops the leak while you sort the origin out.

Closing

Nearly fourteen years ago Sucuri could name PHP.net, Apache.org, Cisco.com, Ford.com and expect readers to be shocked. Every one of those has been fixed since. What has not been fixed is 1,149 other hosts in the CRUX Top 1M that are still shipping their live request tables to anyone who asks. Roughly a third of them do it from behind Cloudflare. One in ten is on an Apache release that hasn't seen a security update since 2018. Some bugs die. This class doesn't.

Download
Article written by
Kirill Efimov
Kirill Efimov is a highly skilled software engineer and security expert with a strong background in software development and team leadership. Currently serving as the Founding Engineer (Security) at Mobb, he brings over a decade of experience to the field of cybersecurity.
LinkedIn
Topics
Fix Research
Security Risks
Subscribe to our newsletter
Commit code fixes

in 60 seconds or less.



That’s the Mobb difference
Book a Demo