dotvitals

Response headers name the application stack

LowConfirmedQuick winweb.security-headers.technology-disclosed

What this check looks for

Headers such as X-Powered-By tell every visitor which framework and version builds your pages. They serve no purpose for the visitor.

Why it matters

These headers exist only to advertise. They cost bytes on every response and hand an attacker the first thing they would otherwise have to work out.

When the check passes, your report says: “Headers give away nothing about the application stack”.

What it costs your score

When this check fails it removes 3 points from your Web security score, before the status, confidence and repeat multipliers are applied. Web security carries a weight of 8 in the overall score.

It shares the web-security.disclosure family ceiling of 10 points: however many findings that family produces, together they cannot remove more than that from Web security. One underlying problem showing up in several places is still one problem.

Severity
low
Default confidence
confirmed
Status when triggered
warn
Deduction
3 points
Family cap
web-security.disclosure · 10
Category
Web security
Module
Web security headers
Fix owned by
user
In the ruleset since
2026.09

How the whole score is calculated

How to fix it

Remove the headers that name your stack.

They benefit nobody but someone enumerating targets.

  1. Remove them at the origin, not only at a proxy — a proxy that is bypassed exposes them again.

  2. PHP: set expose_php = Off in php.ini.

  3. ASP.NET: remove the X-Powered-By custom header and set enableVersionHeader="false".

  4. Express: app.disable('x-powered-by').

How to confirm it worked

  • curl -sSI https://‹host›/ | grep -iE 'x-powered-by|x-aspnet|x-generator|x-runtime' — expect nothing

A named slot like ‹domain› — and the braces left in the configuration below — is filled in with your own values when this rule appears on a report.

Remediation by platform

nginx
# nginx cannot unset a header from an upstream without the headers-more module:
more_clear_headers 'X-Powered-By' 'X-AspNet-Version' 'X-Generator';
Apache
<IfModule mod_headers.c>
	Header always unset X-Powered-By
	Header always unset X-AspNet-Version
</IfModule>
Caddy
header {
	-X-Powered-By
	-X-Generator
}
Express
app.disable('x-powered-by');
  • Without headers-more, remove the header in the application instead — proxy_hide_header only works for headers from a proxied upstream.

  • Shown because the response identified Apache. Prefer the virtual host over .htaccess; and if PHP adds the header, expose_php = Off removes it at the source.

Technical detail

Present: ‹value›.

This rule owns the **response header** case, including a header that carries a product version such as X-Powered-By: WordPress 6.4. The same version published inside the page — in a generator meta tag or in the markup — is reported once, separately, by web.technology.cms-version-disclosed. Neither rule reports the other's channel, so one header is deducted once.

X-Powered-By, X-AspNet-Version, X-Generator and X-Runtime are all removable at the application or server level, and nothing depends on them. Some are added by the runtime rather than the web server — PHP's expose_php and ASP.NET's httpRuntime settings, for instance — so removing them may mean a change in the application's own configuration rather than the server's.

Standards and references

Test this on your domain

Run the check that produces this finding, on its own, against any domain.

Open the web security headers checkerBuild the fix

Other web security headers checks