Skip to content

Release: 5.3.0 - #7468

Open
UlisesGascon wants to merge 1 commit into
masterfrom
release/5.3.0
Open

UlisesGascon wants to merge 1 commit into
masterfrom
release/5.3.0

Conversation

@UlisesGascon

Copy link
Copy Markdown
Member

What's included in the History.md

5.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

* Upgrade `qs` to `^6.15.2`, 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)): an `arrayLimit` bypass in comma parsing allowed a denial of service via arbitrarily large arrays in the query string - by [@davetashner](https://github.com/davetashner) in [#7057](https://github.com/expressjs/express/pull/7057) and [@cyphercodes](https://github.com/cyphercodes) in [#7305](https://github.com/expressjs/express/pull/7305)

## 🚀 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.0`, 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

New Contributors

Full Changelog: v5.2.1...master

@UlisesGascon UlisesGascon self-assigned this Sep 14, 2026
@UlisesGascon UlisesGascon added 5.x release semver-minor This change is a semver minor labels Sep 14, 2026
@UlisesGascon
UlisesGascon requested review from a team, Phillip9587 and bjohansebas September 14, 2026 14:47
@krzysdz

krzysdz commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

#4893, which is included in this release, not only prevents adding Content-Length when Transfer-Encoding is present, but also prevents adding the ETag header. I'm pretty sure that this is an unintended consequence1. There's a PR waiting for review that restores ETag generation - #7459.

Footnotes

  1. Transfer-Encoding is a property of the message, not of the representation, while ETag is the entity tag of the resource representation. If my interpretation of RFC 9110 and RFC 9112 is correct, this means that Transfer-Encoding should not affect ETag in any way.

@bjohansebas bjohansebas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’m not merging it because I only gave it a quick review and didn’t do a thorough analysis. The change looks good to me, though. I left a blocking review, but feel free to dismiss it if the PR is ready to be merged or if we decide not to include this change.

#7459

@UlisesGascon

Copy link
Copy Markdown
Member Author

#7459 is now included in the release 👍

@hoerup

hoerup commented Sep 15, 2026

Copy link
Copy Markdown

might want to fix this before cutting the next release ?
#7473

@YuryShkoda

Copy link
Copy Markdown
Contributor

Thanks for catching this, @krzysdz — and good call on the RFC read, Transfer-Encoding being message-level and ETag being representation-level makes it clear those shouldn't have been coupled. That wasn't intentional on my end, just a side effect of where the body-length calc ended up in #4893. Thanks @cuishuang for the fix in #7459, glad it's in before 5.3.0 ships.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

5.x release semver-minor This change is a semver minor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants