HTTP Header Information Disclosure means your web server announces its product and version in response headers such as Server, X-Powered-By or X-AspNet-Version. It is a low-severity reconnaissance aid, not an exploitable flaw. To hide the server version header, set ServerTokens Prod on Apache, server_tokens off on nginx, removeServerHeader on IIS 10 and expose_php = Off in PHP, then rescan.
What the scanner is actually detecting
Every HTTP response carries headers, and several web servers and frameworks add identifying ones by default. The scanner is not exploiting anything; it simply reads those headers from normal responses and reports what they reveal. Depending on the tool, the finding appears under these titles:
- Tenable Web App Scanning plugin 98618, “HTTP Header Information Disclosure”, severity Info. Tenable describes it as headers that disclose server version and technologies in use.
- ZAP rule 10036, “Server Leaks Version Information via “Server” HTTP Response Header Field”, risk Low, CWE-497. The same rule has an Informational variant, “Server Leaks its Webserver Application via “Server” HTTP Response Header Field”, raised when the header names the product without a version.
- ZAP rule 10061, “X-AspNet-Version Response Header”, risk Low, raised for X-AspNet-Version or X-AspNetMvc-Version.
- ZAP also reports “Server Leaks Information via “X-Powered-By” HTTP Response Header Field(s)” when PHP, ASP.NET or another runtime advertises itself.
| Header | Typical value | Added by |
|---|---|---|
| Server | Apache/2.4.41 (Ubuntu), nginx/1.24.0, Microsoft-IIS/10.0 | The web server itself, or HTTP.sys on Windows |
| X-Powered-By | PHP/8.x, ASP.NET | PHP (expose_php) or the IIS default custom header |
| X-AspNet-Version | 4.0.30319 | ASP.NET on .NET Framework (httpRuntime) |
| X-AspNetMvc-Version | 5.2 | ASP.NET MVC (MvcHandler) |
Real-world risk
Be honest with stakeholders here: this is a hygiene finding. A version string lets an attacker match your server against published CVEs without sending a single probe, which saves them a step. It does not grant access, and automated exploit tooling usually fires payloads regardless of what the banner says. The Apache documentation itself notes that automated tools will still be able to identify the server as Apache after the change, so hiding the version is obscurity, not protection.
The finding matters most when the version shown is genuinely outdated. In that case the banner is the symptom and missing patches are the real problem. It can also mislead in the other direction: enterprise Linux distributions backport fixes without changing the upstream version number, which is covered in our guide to why scanners flag backported patches as vulnerable. Fix the headers because it is cheap and auditors ask for it, but prioritize patching.
How to confirm it on the host
Request a normal page, a missing page and, if you have one, an HTTP to HTTPS redirect. Error and redirect responses are often generated by a different code path than your application pages.
curl -sI https://www.example.com/
curl -s -D - -o /dev/null https://www.example.com/does-not-exist-404
curl -sI http://www.example.com/
On Windows without curl:
(Invoke-WebRequest -Uri 'https://www.example.com/' -UseBasicParsing).Headers
Then check the current configuration on the server:
# Apache (Debian/Ubuntu and RHEL paths)
grep -RiE "ServerTokens|ServerSignature" /etc/apache2/ /etc/httpd/ 2>/dev/null
# nginx: dump the full effective config
sudo nginx -T 2>/dev/null | grep -i server_tokens
# PHP (the CLI may load a different php.ini than PHP-FPM or mod_php)
php -i | grep -i expose_php
How to fix it
Change the header at the layer that creates it. If a reverse proxy or load balancer sits in front, check whether the header comes from the backend and passes through, or from the proxy itself.
Apache httpd
Set both directives at server level. On Debian and Ubuntu they already exist in /etc/apache2/conf-available/security.conf, so edit the values there instead of adding duplicates. On RHEL-family systems use /etc/httpd/conf/httpd.conf or a file under /etc/httpd/conf.d/.
ServerTokens Prod
ServerSignature Off
sudo apachectl configtest
sudo systemctl reload apache2 # or: sudo systemctl reload httpd
ServerTokens Prod reduces the header to Server: Apache. ServerSignature Off removes the version footer from server-generated pages such as error messages and directory listings. Core Apache has no directive that removes the Server header entirely.
nginx
Place the directive in the http block so every server block inherits it (it is also valid in server and location context):
http {
server_tokens off;
# PHP-FPM backends: stop X-Powered-By passing through
fastcgi_hide_header X-Powered-By;
# Proxied backends (Tomcat, Node, Kestrel and so on)
proxy_hide_header X-Powered-By;
}
sudo nginx -t && sudo systemctl reload nginx
The header becomes Server: nginx and error pages stop showing the version. nginx already drops the backend’s own Server header when proxying. Replacing or blanking the header with a custom string is a feature of the commercial subscription, not open source nginx.
IIS 10 and ASP.NET
Microsoft notes that removeServerHeader works only on Windows Server version 1709 / Windows 10 version 1709 and later, so it applies to Windows Server 2019 and 2022 but not to Windows Server 2016 (version 1607). In a site’s web.config:
<configuration>
<system.webServer>
<security>
<requestFiltering removeServerHeader="true" />
</security>
<httpProtocol>
<customHeaders>
<remove name="X-Powered-By" />
</customHeaders>
</httpProtocol>
</system.webServer>
<system.web>
<httpRuntime enableVersionHeader="false" />
</system.web>
</configuration>
To apply the first two settings server-wide in applicationHost.config instead, from an elevated prompt:
%windir%system32inetsrvappcmd.exe add backup "pre-header-hardening"
%windir%system32inetsrvappcmd.exe set config -section:system.webServer/security/requestFiltering /removeServerHeader:"True" /commit:apphost
%windir%system32inetsrvappcmd.exe set config -section:system.webServer/httpProtocol /-"customHeaders.[name='X-Powered-By']" /commit:apphost
X-Powered-By: ASP.NET is defined as a default custom header in applicationHost.config, which is why it has to be removed explicitly. X-AspNetMvc-Version is not a config setting: a developer must set MvcHandler.DisableMvcResponseHeader = true; in Application_Start in Global.asax.
Responses generated by HTTP.sys itself (for example 400 and 503 errors) carry Server: Microsoft-HTTPAPI/2.0 regardless of IIS settings. Microsoft’s Http.sys registry reference documents a DisableServerHeader DWORD: 1 suppresses the header on HTTP.sys-generated responses, 2 stops HTTP.sys from adding one at all.
reg add HKLMSYSTEMCurrentControlSetServicesHTTPParameters /v DisableServerHeader /t REG_DWORD /d 2 /f
The value takes effect only after the HTTP service restarts, which is best done with a server reboot in a maintenance window.
PHP
expose_php can only be set in php.ini. Edit the php.ini used by the web SAPI, then restart PHP-FPM or Apache (for mod_php):
expose_php = Off
Apache Tomcat
In server.xml, leave the Connector’s server attribute unset (Tomcat then sends no Server header unless the application sets one) or set it to a generic value, and keep xpoweredBy at its default of false. To stop default error pages printing the Tomcat version, add this inside the Host element:
<Valve className="org.apache.catalina.valves.ErrorReportValve"
showReport="false" showServerInfo="false" />
How to verify the fix and rescan
- Repeat the curl requests above against the normal page, the 404 page and the redirect. Test each virtual host and each listening port, not just the main site.
- If a CDN or caching proxy sits in front, purge it or test the origin directly, otherwise you may see cached headers.
- Rescan with the tool that raised the finding. ZAP rules 10036 and 10061 are passive, so any fresh crawl through ZAP re-evaluates them. For Tenable WAS, run a new scan of the same target and confirm plugin 98618 no longer lists the version-bearing headers.
What can break and how to roll back
Breakage is rare, but check these before a fleet-wide change:
- Monitoring scripts, inventory tools or load balancer health checks that parse the Server header to detect versions will lose that data. Take versions from package managers or authenticated scans instead.
- Microsoft notes that X-AspNet-Version is used by Visual Studio to detect the ASP.NET version and is not necessary on production sites. Keep it on development servers if developers rely on it.
- Restarting the HTTP service on Windows also stops every HTTP.sys consumer, including IIS and WinRM, so schedule the DisableServerHeader change.
Rollback is a reversal of each step: restore the previous directive values and reload Apache or nginx, run appcmd.exe restore backup “pre-header-hardening” on IIS, delete the DisableServerHeader value and restart, or set expose_php = On and restart PHP.
Common false positive reasons
- The header comes from another layer. A CDN, WAF or load balancer may add its own Server header. Fix it there, or document it if the value reveals no version.
- Product name only. After ServerTokens Prod or server_tokens off, the header still says Apache or nginx. ZAP reports this as the Informational variant of rule 10036; most teams accept it as residual.
- A different code path. The scanner hit a default virtual host, a management port, or an HTTP.sys error response that your change did not cover.
- Stale results. The finding comes from a scan that ran before the change, or from a cached response.
FAQ
Does hiding the server version make my server secure?
No. It removes an easy hint for attackers but does not fix any vulnerability. An outdated server with a hidden banner is still outdated.
Can I remove the Server header completely on Apache or nginx?
Not with core directives. Apache stays at “Apache” and open source nginx stays at “nginx”. Full removal needs an extra module, the commercial nginx subscription, or a front-end proxy that strips the header.
Why is the finding still reported after I changed the config?
Usually because another layer (proxy, CDN, HTTP.sys, Tomcat error pages) still adds a header, or because the scanner reports the name-only variant. Test error pages and every port.
Will hiding versions affect my own vulnerability scans?
Yes, unauthenticated checks that rely on banners become less precise. Use credentialed scans that read installed package versions for accurate results.
Tracking this finding across many hosts
When this finding appears on dozens of web servers, the hard part is knowing which ones are actually fixed. SITEY, a self-hosted vulnerability management platform, imports findings from 16 scanners, merges duplicates reported by the same scanner, and can generate host-specific remediation scripts that its Windows and Linux agents run only after human approval. For findings from Nessus, Acunetix or Burp it can retest the individual finding; for other scanners, import a fresh scan to confirm closure.