Information disclosure
Server, X-Powered-By, and the other headers that leak your stack and versions to attackers, the full list and how to remove them.
Last update:
Some response headers exist only to advertise what software you run. Server
names the web server, often with its exact version and operating system.
X-Powered-By names the backend language or framework. Behind those two sits
a long tail of vendor headers that name the CMS, the cache, the monitoring
agent, or an internal machine. None of them change how the browser renders
the page.
What they do is hand an attacker a free fingerprint of your stack, ready to grep against CVE databases for known exploits. The fix costs one config line per header: remove it, or where the server refuses to drop it, cut it down to a generic value with no version.
HTTP/1.1 200 OK
Server: Apache/2.4.41 (Unix)
X-Powered-By: PHP/8.2.1
Content-Type: text/html; charset=utf-8HTTP/1.1 200 OK
Server: Apache
Content-Type: text/html; charset=utf-8Why banners matter
Fingerprinting the web server is a formal first step of a penetration test.
The OWASP testing guide
(WSTG-INFO-02, Fingerprint Web Server)
calls the technique banner grabbing: send a request, read the response
headers. A header like Server: Apache/2.4.41 (Unix) answers most of the
recon in one line, and as the guide puts it, servers running older versions
of software without up-to-date security patches can be susceptible to known
version-specific exploits.
The workflow is mechanical. An exact version banner, say
X-Powered-By: PHP/5.3.7, goes straight into a CVE database search, which
returns the list of vulnerabilities that version is known to have. Some
disclosure headers give away more than a version. Microsoft Exchange
responses can carry the names of internal front-end and back-end servers
(X-FEServer, X-BEServer, X-CalculatedBETarget), mapping the same
front-end to back-end routing surface that the ProxyLogon exploit chain
(CVE-2021-26855,
analyzed by Google Project Zero) abused.
Be honest about the weight of this finding, though.
MDN
calls obscuring the Server header a measure of debatable benefit, because
attackers can fingerprint a stack by other means, and says the more reliable
approach is to keep the software updated and patched. The
Express security best practices
say the same about disabling X-Powered-By: it does not prevent a
sophisticated attacker from identifying the framework. Removing banners cuts
off the cheapest recon vector and clears the findings every scanner and
pentest report raises; the defense that actually matters is patching.
The headers to remove
Every header in the tables below gets the same advice, remove it, so there is no status column. The canonical inventory is the OWASP Secure Headers Project removal list, 81 headers as of its June 30, 2026 update, which scanners and pentest reports key off. The tables group the most common entries by what they leak; where a header is community-reported rather than officially documented, the description says so.
Server, language, and framework banners
| Header | What it leaks |
|---|---|
Server | The server software, usually its version, sometimes the OS (Apache/2.4.41 (Unix)) |
X-Powered-By | The backend technology, often with a version. PHP sends it when expose_php is on; Express and Next.js send it by default |
X-AspNet-Version | The exact ASP.NET version |
X-AspNetMvc-Version | The ASP.NET MVC version |
X-Php-Version | Reported as a PHP version banner; on the OWASP removal list |
X-Framework, X-Server-Powered-By, X-Content-Encoded-By | Further stack banners on the OWASP removal list, widely reported on Joomla sites |
CMS and platform versions
| Header | What it leaks |
|---|---|
X-Generator | The CMS behind the page; Drupal emits Drupal N |
X-OWA-Version | The exact Exchange Outlook Web Access build number |
X-Umbraco-Version, X-Joomla-Version, X-Powered-CMS, X-CF-Powered-By | Reported as CMS version banners; on the OWASP removal list |
X-Cocoon-Version | Reported as an Apache Cocoon version banner |
Liferay-Portal | Reported as leaking the Liferay edition and version |
OracleCommerceCloud-Version | An Oracle Commerce Cloud banner on the OWASP removal list |
Pega-Host | Reported as leaking an internal Pega node name |
Infrastructure and cache fingerprints
| Header | What it leaks |
|---|---|
X-Varnish | Varnish transaction IDs, one on a cache miss and two on a hit, fingerprinting the cache layer |
X-Turbo-Charged-By | A LiteSpeed family server |
X-Backside-Transport | An IBM DataPower gateway and the status of its backend connection |
K-Proxy-Request | A Knative activator marker, revealing a Kubernetes serverless platform |
Host-Header | Reported as exposing managed-hosting routing information |
Product | On the OWASP removal list |
Internal hostnames
Exchange front-end servers add routing headers to Outlook Web Access and autodiscover responses. These leak internal machine names, which is topology disclosure rather than a version banner, and they sit on the same front-end to back-end routing surface ProxyLogon abused.
| Header | What it leaks |
|---|---|
X-FEServer | The front-end Client Access Server name |
X-BEServer | The back-end server name |
X-CalculatedBETarget | The internal name of the target mailbox server |
X-DiagInfo | The name of the responding mailbox server |
Monitoring agents
The Dynatrace OneAgent family marks responses it has touched, telling an attacker exactly which monitoring stack watches the site.
| Header | What it leaks |
|---|---|
X-OneAgent-JS-Injection | The Dynatrace OneAgent injects its monitoring JavaScript here |
X-ruxit-JS-Agent | The legacy name for the same injection marker |
X-DTAgentId | The Dynatrace agent ID, seen on health-check responses |
X-DTHealthCheck | A Dynatrace health-check marker |
Development and debug artifacts
These go beyond fingerprinting: each one means something from development reached production.
| Header | What it leaks |
|---|---|
SourceMap / X-Sourcemap | The URL of a source map; if the .map file is public, anyone can reconstruct your original unminified client source |
X-SourceFiles | An ASP.NET / IIS Express debug header carrying a base64-encoded local disk path of the source file. It is meant for localhost only, so seeing it in production means a debug configuration leaked |
X-NextJS-Matched-Path | The internal Next.js route pattern that matched, such as /news/[slug] |
X-NextJS-Page | A related Next.js internal header on the OWASP removal list |
X-GitLab-Meta | A JSON blob with a correlation ID and version, observed on GitLab Pages responses |
How to remove them
Each stack has a switch for its own banners. Anything your application or framework adds on top can be stripped by whatever sits in front of it, a reverse proxy or a CDN.
nginx
server_tokens off;
proxy_hide_header X-Powered-By;In nginx,
server_tokens off hides the version in both the Server header and the
built-in error pages, but the header still reads Server: nginx. Removing it
entirely requires the third-party
headers-more module
(more_clear_headers Server;). When proxying, nginx already replaces the
upstream Server header with its own;
proxy_hide_header
drops application headers such as X-Powered-By on the way through.
Apache
ServerTokens Prod
ServerSignature Off
Header always unset X-Powered-ByIn Apache,
ServerTokens Prod trims the banner to Server: Apache and
ServerSignature Off removes the version footer from error pages. Note that
Header unset Server does not remove Apache's own Server header
(Apache Bug 40026);
mod_headers
can only unset headers the application added, such as X-Powered-By.
IIS and ASP.NET
<configuration>
<system.web>
<httpRuntime enableVersionHeader="false" />
</system.web>
<system.webServer>
<security>
<requestFiltering removeServerHeader="true" />
</security>
<httpProtocol>
<customHeaders>
<remove name="X-Powered-By" />
</customHeaders>
</httpProtocol>
</system.webServer>
</configuration>On IIS 10 and later,
removeServerHeader
removes the Server header completely (Windows Server version 1709 and
later). enableVersionHeader="false" drops X-AspNet-Version, and the
customHeaders block removes X-Powered-By. The MVC version banner has its
own switch, set at application start:
MvcHandler.DisableMvcResponseHeader = true;Express
app.disable('x-powered-by');The Express security best practices recommend this line, or using Helmet, which removes the header along with its other header changes.
PHP
expose_php = Offexpose_php can only be set
in php.ini, not at runtime.
Next.js
module.exports = {
poweredByHeader: false,
};The poweredByHeader
option stops Next.js from sending X-Powered-By.
At the CDN or proxy edge
The edge can strip what the origin cannot. On
Cloudflare,
a response header transform rule with the remove operation deletes any of
these headers before the response reaches the visitor, with one caveat: it
cannot remove cf- or x-cf- prefixed headers, nor Cloudflare's own
server header. A reverse proxy or cache you run yourself, such as Varnish,
can likewise unset response headers in its delivery logic. This is often the
fastest fix for vendor headers that a managed platform gives you no switch
for.
Can you remove the Server header entirely
It depends on the server. IIS 10 and later can, with removeServerHeader.
Stock nginx cannot: server_tokens off still sends Server: nginx, and
full removal needs the headers-more module. Apache cannot either;
ServerTokens Prod and its Server: Apache floor is as far as the core
config goes. Behind a CDN the question often disappears, because the edge
substitutes its own banner (Cloudflare sends server: cloudflare, which you
cannot remove). A bare product name with no version is a fine end state; the
version is what feeds the CVE lookup.
Recommendation
Remove or genericize every header in the tables above. The
OWASP HTTP Headers cheat sheet
says it plainly: for Server, "Remove this header or set non-informative
values", and "Remove all X-Powered-By headers". Use the OWASP Secure
Headers Project removal list as the checklist when you sweep your responses.
Keep the finding in perspective. Deleting a banner patches nothing; if the software behind it is outdated, it is exactly as exploitable afterwards. Do this cleanup as hygiene alongside patching, not instead of it. To see which of these headers your site sends today, run it through the security headers scanner.
FAQ
How do I remove X-Powered-By?
It depends on what emits it. In PHP set expose_php = Off; in Express call
app.disable('x-powered-by'); in Next.js set poweredByHeader: false; in IIS
remove it through customHeaders. When you cannot change the origin, strip it
at the reverse proxy or CDN, for example proxy_hide_header X-Powered-By in
nginx.
Is the Server header a vulnerability?
Not by itself. It is an information-disclosure finding: the version banner tells an attacker which software and version to look up in a CVE database, cutting the cheapest recon step. The real risk is running unpatched software behind the banner. Removing it quiets scanners but patches nothing.
Does hiding version banners make my site secure?
No. Stripping Server, X-Powered-By, and the other banners is noise
reduction: it removes the easiest fingerprinting vector and clears scanner
findings. It does not fix a single underlying flaw. As OWASP and MDN both note,
keeping the software patched is the actual defense; banner removal is hygiene
alongside it.
See also
- Security headers overview
- Deprecated headers, the other page whose whole answer is remove: the dead TLS headers HPKP and Expect-CT
- Security headers scanner to check your deployed headers
Sources
- OWASP WSTG-INFO-02, Fingerprint Web Server
- OWASP Secure Headers Project, headers to remove
- OWASP HTTP Headers cheat sheet
- MDN, Server
- MDN, SourceMap
- nginx, ngx_http_core_module (server_tokens)
- Apache, core directives (ServerTokens, ServerSignature)
- IIS, requestFiltering reference
- Express, security best practices
- PHP manual, core php.ini directives (expose_php)
- Next.js, poweredByHeader config reference
- Google Project Zero, CVE-2021-26855 root cause analysis