Response header · non-standard
< X-Powered-By: ExpressX-Powered-By Header: Remove It in Express, PHP, Next.js
X-Powered-By advertises your framework, such as Express or PHP. Remove it in Express, PHP, Next.js, ASP.NET and nginx, and why it is hygiene, not security.
- Direction
- Response
- Category
- Diagnostics
- Spec
- MDN reference
- Status
- Non-standard: Framework convention; safe to remove
On this page
TL;DR:
X-Powered-Byis a non-standard header that frameworks add to name themselves (Express,PHP/8.3.12,ASP.NET). Turn it off in the framework:app.disable('x-powered-by')in Express,expose_php = Offin PHP,poweredByHeader: falsein Next.js. It is hygiene, not security.
What it looks like
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/html; charset=utf-8
HTTP/1.1 200 OK
X-Powered-By: PHP/8.3.12
It is not defined by any RFC, browsers do nothing with it, and the value format is whatever the framework chose. It is a sibling of the Server header; Server names the web server and X-Powered-By names the application layer behind it.
Remove it
Express
import express from 'express'
const app = express()
app.disable('x-powered-by')
Or use Helmet, which removes the header among its defaults:
import helmet from 'helmet'
app.use(helmet())
The Express security guide shows app.disable('x-powered-by'), and says this does not prevent a sophisticated attacker from determining that an app is running Express; it may only discourage a casual exploit.
PHP
; php.ini
expose_php = Off
expose_php defaults to on, which makes PHP send X-Powered-By: PHP/<version>. The PHP manual lists it as changeable in php.ini only, so ini_set() at runtime will not work. Reload PHP-FPM or Apache afterwards.
Next.js
// next.config.js
module.exports = {
poweredByHeader: false
}
Next.js adds x-powered-by: Next.js by default and this option opts out.
ASP.NET and IIS
<!-- web.config -->
<system.webServer>
<httpProtocol>
<customHeaders>
<remove name="X-Powered-By" />
</customHeaders>
</httpProtocol>
</system.webServer>
nginx or Apache in front
When the framework cannot be changed, strip it at the proxy. nginx:
location / {
proxy_pass http://app;
proxy_hide_header X-Powered-By;
}
Apache with mod_headers:
Header always unset X-Powered-By
proxy_hide_header removes the header from the upstream response before it reaches the client. Setting it at the proxy also covers several backends at once.
How much it matters
Honest accounting. Leaving the header on gives an attacker a free hint about the stack. Removing it:
- stops the trivial banner grab and clears automated audit findings,
- does nothing about how the framework behaves: cookie names such as
connect.sidorPHPSESSID, default error pages, route shapes and static file paths all still point to the stack, - does not patch anything.
Do it, because it takes one line, then put your effort into updates, dependency audits and real controls such as Content-Security-Policy and X-Content-Type-Options.
Verify
curl -sI https://example.com | grep -i -E '^(x-powered-by|server)'
Check a 404 and a 500 response as well. Error handlers and upstream proxies sometimes add their own headers separately from the normal path.
Related
- Server for
server_tokens offin nginx andServerTokens Prodin Apache - X-Content-Type-Options, Content-Security-Policy
Frequently asked questions
What is the X-Powered-By header?
A non-standard response header that application frameworks and runtimes add to say what generated the page, for example X-Powered-By: Express, X-Powered-By: PHP/8.3.12 or X-Powered-By: ASP.NET. It is not defined in any RFC and browsers ignore it.
How do I remove X-Powered-By in Express?
Call app.disable("x-powered-by") once at startup, or use the Helmet middleware, which removes the header as part of its defaults. If you disable it on the app and a reverse proxy adds its own copy, remove that one at the proxy.
How do I remove X-Powered-By in PHP?
Set expose_php = Off in php.ini. It can be changed only in php.ini (not with ini_set or .htaccess), and PHP-FPM needs a reload afterwards. A web server or CDN in front can also unset the header, but the PHP setting stops it being generated at all.
Is it dangerous to leave X-Powered-By on?
It tells an attacker which framework and sometimes which version you run, which narrows which known vulnerabilities to try. It is not a vulnerability itself, and removing it does not stop a determined attacker from identifying the stack through other behaviour. Keep software patched; treat removal as small extra hardening.
Does removing X-Powered-By affect SEO or performance?
It does not affect ranking. It saves a few bytes per response, which is negligible for a single request. Some audit tools flag its presence, which is the usual reason to remove it.
Sources
Related
Server Header: Fingerprinting and How to Hide It
The Server header names the software that answered. Use it to find which layer replied, and hide version numbers in nginx, Apache and Cloudflare, with limits.
X-Content-Type-Options Header
Learn how X-Content-Type-Options with nosniff prevents browsers from MIME-sniffing responses. Protect against XSS attacks from content type confusion.
Content-Security-Policy Header: Directives, Nonces and Console Errors
Content-Security-Policy (CSP) limits what a page may load or run. Directives, nonces, strict-dynamic, Report-Only rollout, console errors, helmet and Next.js.
Access-Control-Allow-Credentials Header
Learn how Access-Control-Allow-Credentials controls whether browsers expose responses when credentials (cookies, auth headers) are included in CORS requests.