v5.3.0
expressjs/expressv5.3.0Oct 9, 2026by UlisesGascon
Upgrading?
AI Summary
This release focuses on bug fixes, including HTTP header conflicts and security vulnerabilities, alongside improvements to caching behavior for QUERY requests, error logging, and header handling. It also includes dependency updates to patch CVEs and performance optimizations.
Key Highlights
- Fixed HTTP header conflict between Content-Length and Transfer-Encoding in res.send() to comply with HTTP specifications.
- Added conditional revalidation support for QUERY requests, enabling 304 responses when validators match.
- Upgraded dependencies (qs, body-parser, proxy-addr) to patch multiple CVEs including arrayLimit bypasses and DoS vulnerabilities.
- Improved res.redirect() HTML structure by adding DOCTYPE, title, and body tags for better browser compatibility.
- Enhanced error logging to display the full error object, including nested details and library-specific properties.
Breaking Changes
- Upgrade content-type to ^2.0.0: res.send() now preserves existing parameters when adding charset and does not throw on unparseable Content-Type headers.
- Upgrade content-disposition to ^2.0.1: Content-Disposition headers no longer wrap valid HTTP tokens (filenames) in quotes.
- Upgrade body-parser to ^2.3.0: Invalid limit option values now throw errors at parser initialization instead of being ignored.
New Features
- Conditional revalidation support for QUERY requests.
Full Release Notes
## Highlights
### 🐞 Bug fixes
- Fixed HTTP header conflict between Content-Length and Transfer-Encoding in res.send - by [@YuryShkoda](https://github.com/YuryShkoda) in [#4893](https://github.com/expressjs/express/pull/4893)
Fixed the behavior of `res.send()` to prevent conflicts between `Content-Length` and `Transfer-Encoding` HTTP headers in responses. The `Content-Length` header in `res.send()` is now only added when a `Transfer-Encoding` header is not present, complying with the HTTP specification that states both headers should not coexist in the same response. ETag generation is unaffected by the presence of a `Transfer-Encoding` header - by [@cuishuang](https://github.com/cuishuang) in [#7459](https://github.com/expressjs/express/pull/7459)
* Upgrade `qs` to `^6.16.0`, which fixes [CVE-2026-2391](https://www.cve.org/CVERecord?id=CVE-2026-2391) ([GHSA-w7fw-mjwx-w883](https://github.com/ljharb/qs/security/advisories/GHSA-w7fw-mjwx-w883)), [CVE-2026-82417](https://www.cve.org/CVERecord?id=CVE-2026-82417) ([GHSA-4mjr-xmp4-gh2g](https://github.com/advisories/GHSA-4mjr-xmp4-gh2g)) and [CVE-2026-82562](https://www.cve.org/CVERecord?id=CVE-2026-82562) ([GHSA-x5fp-wj9c-mxmx](https://github.com/advisories/GHSA-x5fp-wj9c-mxmx)): `arrayLimit` bypasses in comma parsing and a denial of service via an attacker-controlled `isBuffer` - by [@davetashner](https://github.com/davetashner) in [#7057](https://github.com/expressjs/express/pull/7057) and [#7478](https://github.com/expressjs/express/pull/7478), and [@cyphercodes](https://github.com/cyphercodes) in [#7305](https://github.com/expressjs/express/pull/7305)
* Upgrade `proxy-addr` to `^2.0.8`, which fixes [CVE-2026-90711](https://www.cve.org/CVERecord?id=CVE-2026-90711) - by [@lazerg](https://github.com/lazerg) in [#7474](https://github.com/expressjs/express/pull/7474)
### 🚀 Improvements
* Allow conditional revalidation for QUERY requests. `req.fresh` previously only validated freshness for GET and HEAD requests, so QUERY responses never returned 304 despite a matching validator. Since QUERY is a safe, idempotent, and cacheable method that supports conditional requests, it is now included in the freshness check - by [@Cherry](https://github.com/Cherry) in [#7366](https://github.com/expressjs/express/pull/7366)
```js
// QUERY /reports with If-None-Match: "12345"
app.query('/reports', (req, res) => {
res.set('ETag', '"12345"');
res.send(results); // now responds 304 Not Modified
});
```
* Improve HTML structure in `res.redirect()` responses when HTML format is accepted by adding `<!DOCTYPE html>`, `<title>`, and `<body>` tags for better browser compatibility - by [@Bernice55231](https://github.com/Bernice55231) in [#5167](https://github.com/expressjs/express/pull/5167)
* When calling `app.render` with options set to null, the locals object is handled correctly, preventing unexpected errors and making the method behave the same as when options is omitted or an empty object is passed - by [AkaHarshit](https://github.com/AkaHarshit) in [#6903](https://github.com/expressjs/express/pull/6903)
```js
app.render('index', null, callback); // now works as expected
```
* Upgrade `content-type` to `^2.0.0`, bringing a faster parser (~1.5x quicker `Content-Type` parsing/formatting in `res.send()`) along with a behavior change: `res.send()` now keeps any existing parameters when adding the charset and no longer throws on a `Content-Type` that fails to parse. `type-is` is upgraded to `^2.1.0` as part of the same change - by [@blakeembrey](https://github.com/blakeembrey) in [#7234](https://github.com/expressjs/express/pull/7234)
```js
res.set('Content-Type', 'text/plain; foo=bar').send('hey');
// -> Content-Type: text/plain; foo=bar; charset=utf-8
```
* The default error handler now logs the full error object instead of only its stack trace, so nested details such as `Error.cause` and library-specific properties (e.g. Sequelize's `parent`/`original`) are no longer swallowed - by [@Nitin-Mohapatra](https://github.com/Nitin-Mohapatra) in [#6464](https://github.com/expressjs/express/pull/6464)
* Upgrade `content-disposition` to `^2.0.1`, which changes the `Content-Disposition` header emitted by `res.download()`, `res.attachment()`, and `res.sendFile()`: file names that are valid HTTP tokens are no longer wrapped in quotes. This is equivalent per RFC 6266, but applications asserting on the exact header bytes should update their expectations - by [@blakeembrey](https://github.com/blakeembrey) in [#7233](https://github.com/expressjs/express/pull/7233)
```js
res.attachment('user.html');
// before -> Content-Disposition: attachment; filename="user.html"
// after -> Content-Disposition: attachment; filename=user.html
```
* Upgrade `body-parser` to `^2.3.0`, which fixes [CVE-2026-12590](https://www.cve.org/CVERecord?id=CVE-2026-12590) ([GHSA-v422-hmwv-36x6](https://github.com/expressjs/body-parser/security/advisories/GHSA-v422-hmwv-36x6)): an invalid `limit` option value caused request body size enforcement to be silently disabled (fail-open), allowing a denial of service via arbitrarily large payloads. Invalid `limit` values now throw at parser initialization instead of being ignored - by [@Mayvis](https://github.com/Mayvis) in [#7390](https://github.com/expressjs/express/pull/7390)
### ⚡ Performance
* Avoid duplicate Content-Type header processing in `res.send()` when sending string responses without an explicit Content-Type header - by [@bjohansebas](https://github.com/bjohansebas) in [#6991](https://github.com/expressjs/express/pull/6991)
## What's Changed
* 📝 add note to history by @ctcpip in https://github.com/expressjs/express/pull/6946
* docs: add @rxmarbles to triagers by @rxmarbles in https://github.com/expressjs/express/pull/6953
* docs: use global Security policy by @UlisesGascon in https://github.com/expressjs/express/pull/6570
* doc: fix security.md link to point to security tab by @jonchurch in https://github.com/expressjs/express/pull/6976
* build(deps): bump actions/download-artifact from 6.0.0 to 7.0.0 by @dependabot[bot] in https://github.com/expressjs/express/pull/6961
* fix: enhance req.acceptsCharsets method by @Abdel-Monaam-Aouini in https://github.com/expressjs/express/pull/6088
* build(deps): bump actions/upload-artifact from 5.0.0 to 6.0.0 by @dependabot[bot] in https://github.com/expressjs/express/pull/6965
* build(deps): bump github/codeql-action from 4.31.6 to 4.31.9 by @dependabot[bot] in https://github.com/expressjs/express/pull/6964
* fix(deps): update version lib qs by @gabrieel1007 in https://github.com/expressjs/express/pull/6969
* build(deps): bump actions/checkout from 6.0.0 to 6.0.1 by @dependabot[bot] in https://github.com/expressjs/express/pull/6963
* build(deps): bump actions/setup-node from 6.0.0 to 6.1.0 by @dependabot[bot] in https://github.com/expressjs/express/pull/6962
* nominate @krzysdz to triage team by @bjohansebas in https://github.com/expressjs/express/pull/6482
* Polish HTML structure of the response in the res.redirect() function by @Bernice55231 in https://github.com/expressjs/express/pull/5167
* docs: fix JSDoc for req.accepts() return value and parameter format by @marcosmol204 in https://github.com/expressjs/express/pull/6936
* test: added unit tests for utils.compileETag to cover valid and invalid inputs by @sukdev24 in https://github.com/expressjs/express/pull/6534
* chore: remove benchmarks directory by @bjohansebas in https://github.com/expressjs/express/pull/6992
* feat: do not modify the Content-Type twice when sending strings by @bjohansebas in https://github.com/expressjs/express/pull/6991
* feat: Allow passing null or undefined as the value for options in app.render by @AkaHarshit in https://github.com/expressjs/express/pull/6903
* test: add test for normalizeType fallback when mime lookup fails by @Ayoub-Mabrouk in https://github.com/expressjs/express/pull/6894
* fix: search example to support Redis v4+ and Express 4/5 by @vinybrun in https://github.com/expressjs/express/pull/6274
* docs: Add @GroophyLifefor to the triage team by @bjohansebas in https://github.com/expressjs/express/pull/6995
* build(deps): bump actions/checkout from 6.0.1 to 6.0.2 by @dependabot[bot] in https://github.com/expressjs/express/pull/7011
* build(deps): bump actions/setup-node from 6.1.0 to 6.2.0 by @dependabot[bot] in https://github.com/expressjs/express/pull/7012
* build(deps): bump github/codeql-action from 4.31.9 to 4.32.0 by @dependabot[bot] in https://github.com/expressjs/express/pull/7013
* Remove duplicate tests in res.location and res.jsonp by @GroophyLifefor in https://github.com/expressjs/express/pull/6996
* fix: bump qs minimum to ^6.14.2 for CVE-2026-2391 by @davetashner in https://github.com/expressjs/express/pull/7057
* docs: fix README security policy by @pavan-sh in https://github.com/expressjs/express/pull/7029
* include edge case tests for `res.type()` by @IshitaSingh0822 in https://github.com/expressjs/express/pull/7037
* build(deps): bump github/codeql-action from 4.32.0 to 4.32.4 by @dependabot[bot] in https://github.com/expressjs/express/pull/7072
* build(deps): bump actions/download-artifact from 7.0.0 to 8.0.0 by @dependabot[bot] in https://github.com/expressjs/express/pull/7073
* build(deps): bump actions/upload-artifact from 6.0.0 to 7.0.0 by @dependabot[bot] in https://github.com/expressjs/express/pull/7074
* docs: replace dummy with placeholder in example comments by @samtuckerdavis in https://github.com/expressjs/express/pull/7064
* docs: remove dead link from Readme by @ayushshukla1807 in https://github.com/expressjs/express/pull/7136
* fix: update deprecated npm install docs URL in Readme.md by @Vansh1811 in https://github.com/expressjs/express/pull/7159
* build(deps): bump actions/download-artifact from 8.0.0 to 8.0.1 by @dependabot[bot] in https://github.com/expressjs/express/pull/7148
* build(deps): bump actions/setup-node from 6.2.0 to 6.3.0 by @dependabot[bot] in https://github.com/expressjs/express/pull/7149
* build(deps): bump github/codeql-action from 4.32.4 to 4.35.1 by @dependabot[bot] in https://github.com/expressjs/express/pull/7150
* fixed typo in history.md by @opensourcezeal in https://github.com/expressjs/express/pull/7191
* chore: ensure safe config in the npmrc by @sheplu in https://github.com/expressjs/express/pull/7144
* ci: build express with node.js v26 by @shivarm in https://github.com/expressjs/express/pull/7218
* build(deps): bump actions/setup-node from 6.3.0 to 6.4.0 by @dependabot[bot] in https://github.com/expressjs/express/pull/7210
* build(deps): bump actions/upload-artifact from 7.0.0 to 7.0.1 by @dependabot[bot] in https://github.com/expressjs/express/pull/7211
* build(deps): bump github/codeql-action from 4.35.1 to 4.35.2 by @dependabot[bot] in https://github.com/expressjs/express/pull/7212
* fix: bump qs minimum to 6.15.2 by @cyphercodes in https://github.com/expressjs/express/pull/7305
* Upgrade `content-type` by @blakeembrey in https://github.com/expressjs/express/pull/7234
* Improve error logging by logging full error object by @Nitin-Mohapatra in https://github.com/expressjs/express/pull/6464
* fix: replace deprecated trimRight() with trimEnd() by @tejgokani in https://github.com/expressjs/express/pull/7265
* build(deps): bump github/codeql-action from 4.35.2 to 4.36.0 by @dependabot[bot] in https://github.com/expressjs/express/pull/7297
* Upgrade `content-disposition` by @blakeembrey in https://github.com/expressjs/express/pull/7233
* fix(res.send): add Content-Length header only if Transfer-Encoding is not present by @YuryShkoda in https://github.com/expressjs/express/pull/4893
* docs: use the new logo by @bjohansebas in https://github.com/expressjs/express/pull/7316
* build(deps): bump actions/checkout from 6.0.2 to 7.0.0 by @dependabot[bot] in https://github.com/expressjs/express/pull/7345
* build(deps-dev): bump morgan from 1.10.1 to 1.11.0 by @dependabot[bot] in https://github.com/expressjs/express/pull/7353
* feat: allow conditional revalidation for QUERY requests by @Cherry in https://github.com/expressjs/express/pull/7366
* build(deps-dev): bump hbs from 4.2.0 to 4.2.1 by @dependabot[bot] in https://github.com/expressjs/express/pull/7152
* deps: bump body-parser to ^2.3.0 to fix CVE-2026-12590 by @Mayvis in https://github.com/expressjs/express/pull/7390
* build(deps): bump actions/checkout from 7.0.0 to 7.0.1 by @dependabot[bot] in https://github.com/expressjs/express/pull/7403
* docs(res.location): clean up deprecated back string references by @spellsaif in https://github.com/expressjs/express/pull/7406
* build(deps): bump coverallsapp/github-action from 2.3.7 to 2.3.8 by @dependabot[bot] in https://github.com/expressjs/express/pull/7399
* build(deps): bump github/codeql-action/upload-sarif from 4.36.0 to 4.37.3 by @dependabot[bot] in https://github.com/expressjs/express/pull/7400
* chore: group github actions updates by @Phillip9587 in https://github.com/expressjs/express/pull/7460
* build(deps-dev): bump hbs from 4.2.1 to 4.3.0 by @dependabot[bot] in https://github.com/expressjs/express/pull/7450
* build(deps): bump the github-actions group with 5 updates by @dependabot[bot] in https://github.com/expressjs/express/pull/7462
* build(deps-dev): bump morgan from 1.11.0 to 1.12.0 by @dependabot[bot] in https://github.com/expressjs/express/pull/7461
* docs: fix capitalization of GitHub Discussions in Readme by @Kimkoungsoo in https://github.com/expressjs/express/pull/7426
* ci: add npm staged publication with dist-tag support by @UlisesGascon in https://github.com/expressjs/express/pull/7464
* fix(res.send): preserve ETag generation with Transfer-Encoding by @cuishuang in https://github.com/expressjs/express/pull/7459
* deps: proxy-addr@^2.0.8 by @lazerg in https://github.com/expressjs/express/pull/7474
* deps: bump qs minimum to 6.16.0 by @davetashner in https://github.com/expressjs/express/pull/7478
* build(deps-dev): bump morgan from 1.12.0 to 1.12.1 by @dependabot[bot] in https://github.com/expressjs/express/pull/7493
* docs: add missing apostrophe in "can\u0027t" (lib + example) by @haimingZZ in https://github.com/expressjs/express/pull/7483
* build(deps-dev): bump hbs from 4.3.0 to 4.3.1 by @dependabot[bot] in https://github.com/expressjs/express/pull/7500
* build(deps): bump the github-actions group with 3 updates by @dependabot[bot] in https://github.com/expressjs/express/pull/7499
* docs: fix pass-through typos by @whoalin1 in https://github.com/expressjs/express/pull/7509
* docs: fix typos and a stale API reference in lib comments by @fmtappendf in https://github.com/expressjs/express/pull/7512
* Release: 5.3.0 by @UlisesGascon in https://github.com/expressjs/express/pull/7468
## New Contributors
* @rxmarbles made their first contribution in https://github.com/expressjs/express/pull/6953
* @gabrieel1007 made their first contribution in https://github.com/expressjs/express/pull/6969
* @Bernice55231 made their first contribution in https://github.com/expressjs/express/pull/5167
* @marcosmol204 made their first contribution in https://github.com/expressjs/express/pull/6936
* @sukdev24 made their first contribution in https://github.com/expressjs/express/pull/6534
* @AkaHarshit made their first contribution in https://github.com/expressjs/express/pull/6903
* @vinybrun made their first contribution in https://github.com/expressjs/express/pull/6274
* @GroophyLifefor made their first contribution in https://github.com/expressjs/express/pull/6996
* @davetashner made their first contribution in https://github.com/expressjs/express/pull/7057
* @pavan-sh made their first contribution in https://github.com/expressjs/express/pull/7029
* @IshitaSingh0822 made their first contribution in https://github.com/expressjs/express/pull/7037
* @samtuckerdavis made their first contribution in https://github.com/expressjs/express/pull/7064
* @ayushshukla1807 made their first contribution in https://github.com/expressjs/express/pull/7136
* @Vansh1811 made their first contribution in https://github.com/expressjs/express/pull/7159
* @opensourcezeal made their first contribution in https://github.com/expressjs/express/pull/7191
* @cyphercodes made their first contribution in https://github.com/expressjs/express/pull/7305
* @Nitin-Mohapatra made their first contribution in https://github.com/expressjs/express/pull/6464
* @tejgokani made their first contribution in https://github.com/expressjs/express/pull/7265
* @YuryShkoda made their first contribution in https://github.com/expressjs/express/pull/4893
* @Mayvis made their first contribution in https://github.com/expressjs/express/pull/7390
* @spellsaif made their first contribution in https://github.com/expressjs/express/pull/7406
* @Kimkoungsoo made their first contribution in https://github.com/expressjs/express/pull/7426
* @cuishuang made their first contribution in https://github.com/expressjs/express/pull/7459
* @haimingZZ made their first contribution in https://github.com/expressjs/express/pull/7483
* @whoalin1 made their first contribution in https://github.com/expressjs/express/pull/7509
* @fmtappendf made their first contribution in https://github.com/expressjs/express/pull/7512
**Full Changelog**: https://github.com/expressjs/express/compare/v5.2.1...v5.3.0Related Repositories
affaan-m/ECC★ 285,830
The agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.
react/react★ 251,627
The library for web and native user interfaces.
nodejs/node★ 122,523
Node.js JavaScript runtime ✨🐢🚀✨
Leonxlnx/taste-skill★ 100,669
Agent skills that give coding agents taste: art direction, reference images and a browser check instead of generic AI pages
louislam/uptime-kuma★ 92,730
A fancy self-hosted monitoring tool