diff --git a/History.md b/History.md index 287a8522d63..57128776594 100644 --- a/History.md +++ b/History.md @@ -1,3 +1,8 @@ +5.2.1 / 2025-12-01 +======================= + +* 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)) + 5.2.0 / 2025-12-01 ======================== diff --git a/lib/utils.js b/lib/utils.js index 4b227f0057c..4f21e7ef1e3 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -266,6 +266,6 @@ function createETagGenerator (options) { function parseExtendedQueryString(str) { return qs.parse(str, { - plainObjects: true + allowPrototypes: true }); } diff --git a/package.json b/package.json index ade9ed9d6af..8f358830d97 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "express", "description": "Fast, unopinionated, minimalist web framework", - "version": "5.2.0", + "version": "5.2.1", "author": "TJ Holowaychuk ", "contributors": [ "Aaron Heckmann ", diff --git a/test/req.query.js b/test/req.query.js index 176dc991b5a..c0d3c8376e9 100644 --- a/test/req.query.js +++ b/test/req.query.js @@ -3,7 +3,6 @@ var assert = require('node:assert') var express = require('../') , request = require('supertest'); -var qs = require('qs'); describe('req', function(){ describe('.query', function(){ @@ -39,22 +38,6 @@ describe('req', function(){ .get('/?user.name=tj') .expect(200, '{"user.name":"tj"}', done); }); - - it('should not be able to access object prototype properties', function (done) { - var app = createApp('extended', true); - - request(app) - .get('/?foo=yee') - .expect(200, /TypeError: req\.query\.hasOwnProperty is not a function/, done); - }); - - it('should be able to use object prototype property names as keys', function (done) { - var app = createApp('extended', true); - - request(app) - .get('/?hasOwnProperty=yee') - .expect(200, '{"query":{"hasOwnProperty":"yee"},"error":"TypeError: req.query.hasOwnProperty is not a function"}', done); - }); }); describe('when "query parser" is simple', function () { @@ -65,22 +48,6 @@ describe('req', function(){ .get('/?user%5Bname%5D=tj') .expect(200, '{"user[name]":"tj"}', done); }); - - it('should not be able to access object prototype properties', function (done) { - var app = createApp('simple', true); - - request(app) - .get('/?foo=yee') - .expect(200, /TypeError: req\.query\.hasOwnProperty is not a function/, done); - }); - - it('should be able to use object prototype property names as keys', function (done) { - var app = createApp('simple', true); - - request(app) - .get('/?hasOwnProperty=yee') - .expect(200, '{"query":{"hasOwnProperty":"yee"},"error":"TypeError: req.query.hasOwnProperty is not a function"}', done); - }); }); describe('when "query parser" is a function', function () { @@ -93,18 +60,6 @@ describe('req', function(){ .get('/?user%5Bname%5D=tj') .expect(200, '{"length":17}', done); }); - - // test exists to verify behavior for folks wishing to workaround our qs defaults - it('should drop object prototype property names and be able to access object prototype properties', function (done) { - var app = createApp( - function (str) { - return qs.parse(str) - }, true); - - request(app) - .get('/?hasOwnProperty=biscuits') - .expect(200, '{"query":{},"hasOwnProperty":false}', done); - }); }); describe('when "query parser" disabled', function () { @@ -115,22 +70,6 @@ describe('req', function(){ .get('/?user%5Bname%5D=tj') .expect(200, '{}', done); }); - - it('should not be able to access object prototype properties', function (done) { - var app = createApp('extended', true); - - request(app) - .get('/?foo=yee') - .expect(200, /TypeError: req\.query\.hasOwnProperty is not a function/, done); - }); - - it('should be able to use object prototype property names as keys', function (done) { - var app = createApp('extended', true); - - request(app) - .get('/?hasOwnProperty=yee') - .expect(200, '{"query":{"hasOwnProperty":"yee"},"error":"TypeError: req.query.hasOwnProperty is not a function"}', done); - }); }); describe('when "query parser" enabled', function () { @@ -141,22 +80,6 @@ describe('req', function(){ .get('/?user%5Bname%5D=tj') .expect(200, '{"user[name]":"tj"}', done); }); - - it('should not be able to access object prototype properties', function (done) { - var app = createApp('extended', true); - - request(app) - .get('/?foo=yee') - .expect(200, /TypeError: req\.query\.hasOwnProperty is not a function/, done); - }); - - it('should be able to use object prototype property names as keys', function (done) { - var app = createApp('extended', true); - - request(app) - .get('/?hasOwnProperty=yee') - .expect(200, '{"query":{"hasOwnProperty":"yee"},"error":"TypeError: req.query.hasOwnProperty is not a function"}', done); - }); }); describe('when "query parser" an unknown value', function () { @@ -168,7 +91,7 @@ describe('req', function(){ }) }) -function createApp(setting, isPrototypePropertyTest) { +function createApp(setting) { var app = express(); if (setting !== undefined) { @@ -176,17 +99,7 @@ function createApp(setting, isPrototypePropertyTest) { } app.use(function (req, res) { - if(isPrototypePropertyTest) { - try { - var hasOwnProperty = req.query.hasOwnProperty('✨ express ✨'); - res.send({ query: req.query, hasOwnProperty: hasOwnProperty }); - } catch (error) { - res.send({ query: req.query, error: error.toString() }); - } - } - else { - res.send(req.query); - } + res.send(req.query); }); return app;