How do I remove the X-Powered-By header?
The X-Powered-By header is a non-standard response header that names the application or framework that generated the response, and Express apps send it by default as X-Powered-By: express. It is a fingerprinting hint rather than a feature, and removing it takes one line in most stacks.
Why this matters
Knowing that a site runs Express, or any other framework, narrows an attacker’s search for the vulnerabilities that apply. Framework-specific middleware, templating bugs and known CVEs can all be tried first instead of guessed at, and an automated scanner will happily classify the target and select its payloads accordingly. Express’s own guidance is measured about this: disabling the header does not stop a sophisticated attacker from working out that an app runs Express, but it may discourage a casual exploit. That is the right way to think about it. Removing the header costs nothing, removes an easy signal from the response, and raises the effort required for low-effort attacks. It does not change the fact that the app still needs to be patched and configured securely, so treat this as one quiet signal among many rather than a security boundary in itself. The header can also name more than one layer at once: some PHP deployments send X-Powered-By: PHP/8.2, and other frameworks append their own tokens, so a single field can reveal several components of the stack.
How to fix it
Each stack has its own switch. Express exposes app.disable('x-powered-by'), Next.js has the poweredByHeader option in next.config.js, and a static host or edge can strip the header at the response layer. If your app runs behind Apache and something upstream still emits the header, mod_headers can unset it there too. These switches operate at different layers, so if your stack has more than one of them, apply the setting where the header is actually generated rather than only stripping it after the fact.
// Express
app.disable('x-powered-by');
// Next.js — next.config.js
module.exports = {
poweredByHeader: false,
}
# Cloudflare Pages _headers: detach the header
/*
! X-Powered-By
// Cloudflare Workers: delete the header from the response
const newResponse = new Response(response.body, response);
newResponse.headers.delete("X-Powered-By");
# Apache: strip it at the edge with mod_headers
Header unset X-Powered-By
How to verify the fix
Fetch the response headers and confirm that no X-Powered-By line comes back. If the header is still present, check whether a proxy or framework is adding it after your change, since edge rules only affect responses that pass through them. The DevTools Network panel shows the same field for any request. Some frameworks only emit the header on certain routes, so confirm a few different URLs rather than a single page, and check an error or 404 response too, since those paths are often probed first. Repeat the check after any framework upgrade, since defaults can quietly return.
curl -sI https://example.com | findstr /I "x-powered-by"
Automated check
The automated check inspects your response headers and reports X-Powered-By header exposes stack as a Medium-severity finding when the header is present, for example when it reads express. It flags the disclosure itself; deciding whether a given framework version is exploitable in your deployment is a separate judgement you make after patching.