Fixed HTTP header conflict between Content-Length and Transfer-Encoding in res.send - by @YuryShkoda in #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 in #7459
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 in #7366
// 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 in #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 in #6903
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 in #7234
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 in #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 in #7233
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 (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 in #7390
⚡ Performance
Avoid duplicate Content-Type header processing in res.send() when sending string responses without an explicit Content-Type header - by @bjohansebas in #6991
The prior release (5.2.0) included an erroneous breaking change related to the extended query parser. There is no actual security vulnerability associated with this behavior (CVE-2024-51999 has been rejected). The change has been fully reverted in this release.
A deprecation warning was added when using res.redirect with undefined arguments, Express now emits a warning to help detect calls that pass undefined as the status or URL and make them easier to fix.
This PR contains the following updates:
| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [express](https://expressjs.com/) ([source](https://github.com/expressjs/express)) | [`^4.21.2` → `^5.0.0`](https://renovatebot.com/diffs/npm/express/4.22.3/5.3.0) |  |  |
---
### Release Notes
<details>
<summary>expressjs/express (express)</summary>
### [`v5.3.0`](https://github.com/expressjs/express/blob/HEAD/History.md#530)
[Compare Source](https://github.com/expressjs/express/compare/v5.2.1...v5.3.0)
\=====
#### 🐞 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)
### [`v5.2.1`](https://github.com/expressjs/express/blob/HEAD/History.md#521)
[Compare Source](https://github.com/expressjs/express/compare/v5.2.0...v5.2.1)
\=====
- Revert security fix for [CVE-2024-51999](https://www.cve.org/CVERecord?id=CVE-2024-51999) ([GHSA-pj86-cfqh-vqx6](https://github.com/expressjs/express/security/advisories/GHSA-pj86-cfqh-vqx6))
- The prior release (5.2.0) included an erroneous breaking change related to the extended query parser. There is no actual security vulnerability associated with this behavior (CVE-2024-51999 has been rejected). The change has been fully reverted in this release.
### [`v5.2.0`](https://github.com/expressjs/express/blob/HEAD/History.md#520)
[Compare Source](https://github.com/expressjs/express/compare/v5.1.0...v5.2.0)
\=====
- Security fix for [CVE-2024-51999](https://www.cve.org/CVERecord?id=CVE-2024-51999) ([GHSA-pj86-cfqh-vqx6](https://github.com/expressjs/express/security/advisories/GHSA-pj86-cfqh-vqx6))
- deps: `body-parser@^2.2.1`
- A deprecation warning was added when using `res.redirect` with undefined arguments, Express now emits a warning to help detect calls that pass undefined as the status or URL and make them easier to fix.
### [`v5.1.0`](https://github.com/expressjs/express/blob/HEAD/History.md#510)
[Compare Source](https://github.com/expressjs/express/compare/v5.0.1...v5.1.0)
\=====
- Add support for `Uint8Array` in `res.send()`
- Add support for ETag option in `res.sendFile()`
- Add support for multiple links with the same rel in `res.links()`
- Add funding field to package.json
- perf: use loop for acceptParams
- refactor: prefix built-in node module imports
- deps: remove `setprototypeof`
- deps: remove `safe-buffer`
- deps: remove `utils-merge`
- deps: remove `methods`
- deps: remove `depd`
- deps: `debug@^4.4.0`
- deps: `body-parser@^2.2.0`
- deps: `router@^2.2.0`
- deps: `content-type@^1.0.5`
- deps: `finalhandler@^2.1.0`
- deps: `qs@^6.14.0`
- deps: `server-static@2.2.0`
- deps: `type-is@2.0.1`
### [`v5.0.1`](https://github.com/expressjs/express/blob/HEAD/History.md#501)
[Compare Source](https://github.com/expressjs/express/compare/v5.0.0...v5.0.1)
\=====
- Update `cookie` semver lock to address [CVE-2024-47764](https://nvd.nist.gov/vuln/detail/CVE-2024-47764)
### [`v5.0.0`](https://github.com/expressjs/express/blob/HEAD/History.md#500)
[Compare Source](https://github.com/expressjs/express/compare/v4.22.3...v5.0.0)
\=====
- remove:
- `path-is-absolute` dependency - use `path.isAbsolute` instead
- breaking:
- `res.status()` accepts only integers, and input must be greater than 99 and less than 1000
- will throw a `RangeError: Invalid status code: ${code}. Status code must be greater than 99 and less than 1000.` for inputs outside this range
- will throw a `TypeError: Invalid status code: ${code}. Status code must be an integer.` for non integer inputs
- deps: send\@​1.0.0
- `res.redirect('back')` and `res.location('back')` is no longer a supported magic string, explicitly use `req.get('Referrer') || '/'`.
- change:
- `res.clearCookie` will ignore user provided `maxAge` and `expires` options
- deps: cookie-signature@^1.2.1
- deps: debug\@​4.3.6
- deps: merge-descriptors@^2.0.0
- deps: serve-static@^2.1.0
- deps: qs\@​6.13.0
- deps: accepts@^2.0.0
- deps: mime-types@^3.0.0
- `application/javascript` => `text/javascript`
- deps: type-is@^2.0.0
- deps: content-disposition@^1.0.0
- deps: finalhandler@^2.0.0
- deps: fresh@^2.0.0
- deps: body-parser@^2.0.1
- deps: send@^1.1.0
</details>
---
### Configuration
📅 **Schedule**: (UTC)
- Branch creation
- At any time (no schedule defined)
- Automerge
- At any time (no schedule defined)
🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.
♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 **Ignore**: Close this PR and you won't be reminded about this update again.
---
- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box
---
This PR has been generated by [Mend Renovate CLI](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4xNzguMSIsInVwZGF0ZWRJblZlciI6IjQ0LjE3OC4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJkZXBlbmRlbmNpZXMiLCJyZW5vdmF0ZSJdfQ==-->
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
This PR contains the following updates:
^4.21.2→^5.0.0Release Notes
expressjs/express (express)
v5.3.0Compare Source
=====
🐞 Bug fixes
Fixed HTTP header conflict between Content-Length and Transfer-Encoding in res.send - by @YuryShkoda in #4893
Fixed the behavior of
res.send()to prevent conflicts betweenContent-LengthandTransfer-EncodingHTTP headers in responses. TheContent-Lengthheader inres.send()is now only added when aTransfer-Encodingheader 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 aTransfer-Encodingheader - by @cuishuang in #7459Upgrade
qsto^6.16.0, which fixes CVE-2026-2391 (GHSA-w7fw-mjwx-w883), CVE-2026-82417 (GHSA-4mjr-xmp4-gh2g) and CVE-2026-82562 (GHSA-x5fp-wj9c-mxmx):arrayLimitbypasses in comma parsing and a denial of service via an attacker-controlledisBuffer- by @davetashner in #7057 and #7478, and @cyphercodes in #7305Upgrade
proxy-addrto^2.0.8, which fixes CVE-2026-90711 - by @lazerg in #7474🚀 Improvements
Allow conditional revalidation for QUERY requests.
req.freshpreviously 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 in #7366Improve 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 in #5167When calling
app.renderwith 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 in #6903Upgrade
content-typeto^2.0.0, bringing a faster parser (~1.5x quickerContent-Typeparsing/formatting inres.send()) along with a behavior change:res.send()now keeps any existing parameters when adding the charset and no longer throws on aContent-Typethat fails to parse.type-isis upgraded to^2.1.0as part of the same change - by @blakeembrey in #7234The default error handler now logs the full error object instead of only its stack trace, so nested details such as
Error.causeand library-specific properties (e.g. Sequelize'sparent/original) are no longer swallowed - by @Nitin-Mohapatra in #6464Upgrade
content-dispositionto^2.0.1, which changes theContent-Dispositionheader emitted byres.download(),res.attachment(), andres.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 in #7233Upgrade
body-parserto^2.3.0, which fixes CVE-2026-12590 (GHSA-v422-hmwv-36x6): an invalidlimitoption value caused request body size enforcement to be silently disabled (fail-open), allowing a denial of service via arbitrarily large payloads. Invalidlimitvalues now throw at parser initialization instead of being ignored - by @Mayvis in #7390⚡ Performance
res.send()when sending string responses without an explicit Content-Type header - by @bjohansebas in #6991v5.2.1Compare Source
=====
v5.2.0Compare Source
=====
body-parser@^2.2.1res.redirectwith undefined arguments, Express now emits a warning to help detect calls that pass undefined as the status or URL and make them easier to fix.v5.1.0Compare Source
=====
Uint8Arrayinres.send()res.sendFile()res.links()setprototypeofsafe-bufferutils-mergemethodsdepddebug@^4.4.0body-parser@^2.2.0router@^2.2.0content-type@^1.0.5finalhandler@^2.1.0qs@^6.14.0server-static@2.2.0type-is@2.0.1v5.0.1Compare Source
=====
cookiesemver lock to address CVE-2024-47764v5.0.0Compare Source
=====
path-is-absolutedependency - usepath.isAbsoluteinsteadres.status()accepts only integers, and input must be greater than 99 and less than 1000RangeError: Invalid status code: ${code}. Status code must be greater than 99 and less than 1000.for inputs outside this rangeTypeError: Invalid status code: ${code}. Status code must be an integer.for non integer inputsres.redirect('back')andres.location('back')is no longer a supported magic string, explicitly usereq.get('Referrer') || '/'.res.clearCookiewill ignore user providedmaxAgeandexpiresoptionsapplication/javascript=>text/javascriptConfiguration
📅 Schedule: (UTC)
🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.
♻ Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.
🔕 Ignore: Close this PR and you won't be reminded about this update again.
This PR has been generated by Mend Renovate CLI.
1822fdec64to632df9b0bc632df9b0bctoc1fe3fdd76