expressjs/express
Security
Active contributors: dougwilson, ulisesgascon, wesleytodd
Express runs on the public internet by default. The framework's small footprint puts most of the security responsibility on application code and on the dependencies it integrates. This page lists what the project itself does and the patterns the codebase uses to stay safe.
Reporting vulnerabilities
Use the security policy and GitHub's private vulnerability reporting workflow. Do not open public issues. The Readme.md has the canonical link.
Repository-level controls
- CodeQL —
.github/workflows/codeql.ymlruns GitHub's static analysis on every push and pull request. - OpenSSF Scorecard —
.github/workflows/scorecard.ymlposts a supply-chain hygiene score; the badge is displayed at the top ofReadme.md. - Dependabot —
.github/dependabot.ymlkeeps Actions and runtime dependencies bumped. Roughly half of the last 50 commits tomasterare dependency bumps (see By the numbers). persist-credentials: false— Every workflow checkout uses this to avoid leaking theGITHUB_TOKENto subsequent steps.- Pinned action SHAs — Actions in CI workflows are referenced by commit SHA with a version comment (e.g.,
actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2). This is enforced manually but is consistent.
CVEs in recent history
| Date | Affected | Notes |
|---|---|---|
| 2024-10-08 | cookie semver lock |
Express 5.0.1: bumped cookie-signature to address CVE-2024-47764. |
| 2025-12-01 | (rejected) CVE-2024-51999 | Express 5.2.0 attempted a fix; 5.2.1 reverted it on the same day after the CVE was rejected and the fix proved to be a breaking change to the extended query parser. See History.md. |
| 2026-XX (master) | qs minimum version |
fix: bump qs minimum to ^6.14.2 for CVE-2026-2391 lands as commit 925a1dff on master, ahead of the next release. |
The full history of security-related changes is preserved in History.md.
Built-in security-relevant behaviour
X-Powered-By header
app.handle in lib/application.js sets X-Powered-By: Express on every response when the 'x-powered-by' setting is enabled (the default). To remove it:
app.disable('x-powered-by');res.jsonp Rosetta Flash mitigation
res.jsonp (lib/response.js) prepends /**/ to its output and sets X-Content-Type-Options: nosniff. This prevents browsers from misinterpreting the response as a Flash file (Rosetta Flash attack class). It also escapes \u2028 and \u2029 in the body to avoid breaking out of JSON in older JS parsers.
The callback name from the query string is sanitised against /[^\[\]\w$.]/g so only \w, $, ., [, and ] survive.
res.redirect body
res.redirect builds an HTML body that includes a <title> and <body> (added in master post-5.2). The URL is HTML-escaped via the escape-html package before insertion. The Location header itself is encoded by encodeurl.
res.status strictness
Express 5 made res.status strict: only integers in [100, 999] are accepted. Out-of-range or non-integer values throw. This eliminates a class of bugs where a typo (res.status('200'), res.status(2000)) would silently propagate.
Trust proxy
The 'trust proxy' setting decides whether X-Forwarded-* headers are honoured. Default is false — Express does not trust forwarded headers unless you opt in. Misconfiguring this is a common cause of bypassed rate-limiting or IP-restricted endpoints. Configure it to match the count of trusted hops in front of your app, or to a CIDR list.
Cookies
res.cookierequiresreq.secretforsigned: true. There is no fallback default secret.res.clearCookieignores user-providedmaxAge/expires(Express 5) so a stale config can't accidentally re-extend a "cleared" cookie.- Always set
httpOnlyandsecurefor session-related cookies in production. The framework does not do this for you.
Body parsing limits
express.json and friends accept a limit option. The default is '100kb' (set inside body-parser). Large file uploads should not flow through these parsers — use a dedicated multipart library or a streaming approach.
Application-level recommendations
The expressjs/expressjs.com documentation has a dedicated security guide (Security Best Practices). High-level recommendations include:
- Use
helmetto set sane HTTP security headers. - Use HTTPS in production (terminate at a reverse proxy or
https.createServer). - Don't disable
etagunless you have a reason — caches help mitigate certain DoS patterns. - Validate user input — Express does not sanitise request bodies for you.
- Pin or audit your
qs/body-parsermajor versions for prototype-pollution risk.
Related pages
- Lore for the timeline of dependency upgrades and CVEs.
- Reference / Dependencies for the runtime dependency list.
- Patterns and conventions for the error-handling style.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.