Express Open Redirect vulnerability
Research is free — Hunters explains how the bug works, the root-cause code pattern, how the fix addresses it, and how to test whether a target is affected, in chat. Investigate & write exploit is a paid run — the engine reads the advisory and fix commits, then builds and validates a working proof-of-concept exploit with reproduction steps.
Affected versions
3.4.5 → fixed in 4.0.0-rc1
Details
URL Redirection to Untrusted Site ('Open Redirect') vulnerability in Express. This vulnerability affects the use of the Express Response object. This issue impacts Express: from 3.4.5 before 4.0.0-rc1.
The fix
no semver2 so travis stops crying
package.json+1 −1
@@ -43,7 +43,7 @@"should": "2","connect-redis": "*","marked": "*",-"supertest": "0.8.1 - 1"+"supertest": ">= 0.8.1 < 1"},"keywords": ["express",lib/response.js | 2 +-test/res.send.js | 15 +++++++++++++++2 files changed, 16 insertions(+), 1 deletion(-)
lib/response.js+1 −1
@@ -132,7 +132,7 @@ res.send = function(body){// ETag support// TODO: W/ support-if (app.settings.etag && len > 1024 && 'GET' == req.method) {+if (app.settings.etag && len && 'GET' == req.method) {if (!this.get('ETag')) {this.set('ETag', etag(body));}
test/res.send.js+15 −0
@@ -321,6 +321,21 @@ describe('res', function(){describe('"etag" setting', function(){describe('when enabled', function(){+it('should send ETag even when content-length < 1024', function(done){+var app = express();++app.use(function(req, res){+res.send('kajdslfkasdf');+});++request(app)+.get('/')+.end(function(err, res){+res.headers.should.have.property('etag');+done();+});+})+it('should send ETag ', function(done){var app = express();test/res.sendfile.js | 2 +-1 file changed, 1 insertion(+), 1 deletion(-)
test/res.sendfile.js+1 −1
@@ -51,7 +51,7 @@ describe('res', function(){.get('/').end(function(err, res){assert(1 == calls, 'called too many times');-res.text.should.equal("ENOENT, stat 'test/fixtures/nope.html'");+res.text.should.startWith("ENOENT, stat");res.statusCode.should.equal(200);done();});.travis.yml | 2 ++package.json | 18 +++++++++---------2 files changed, 11 insertions(+), 9 deletions(-)
.travis.yml+2 −0
@@ -2,3 +2,5 @@ language: node_jsnode_js:- "0.8"- "0.10"+before_install:+- "npm update -g npm"
package.json+9 −9
@@ -32,18 +32,18 @@"methods": "0.1.0","send": "0.1.4","cookie-signature": "1.0.1",-"debug": "*"+"debug": "0.7.3 - 1"},"devDependencies": {-"ejs": "*",-"mocha": "*",+"ejs": "0.8.4 - 1",+"mocha": "^1.13.0","jade": "0.30.0",-"hjs": "*",-"stylus": "*",-"should": "2",-"connect-redis": "*",-"marked": "*",-"supertest": ">= 0.8.1 < 1"+"hjs": "0.0.6 - 1",+"stylus": "0.39.1 - 1",+"should": "^2.0.2",+"connect-redis": "^1.4.5",+"marked": "0.2.9 - 1",+"supertest": "0.8.1 - 1"},"keywords": ["express",.travis.yml | 4 +---package.json | 20 ++++++++++----------2 files changed, 11 insertions(+), 13 deletions(-)
.travis.yml+1 −3
@@ -1,6 +1,4 @@language: node_jsnode_js:- "0.8"-- "0.10"-before_install:-- "npm update -g npm"+- "0.10"
package.json+10 −10
@@ -32,18 +32,18 @@"methods": "0.1.0","send": "0.1.4","cookie-signature": "1.0.1",-"debug": "0.7.3 - 1"+"debug": ">= 0.7.3 < 1"},"devDependencies": {-"ejs": "0.8.4 - 1",-"mocha": "^1.13.0",+"ejs": ">= 0.8.4 < 1",+"mocha": ">= 1.13.0 < 2","jade": "0.30.0",-"hjs": "0.0.6 - 1",-"stylus": "0.39.1 - 1",-"should": "^2.0.2",-"connect-redis": "^1.4.5",-"marked": "0.2.9 - 1",-"supertest": "0.8.1 - 1"+"hjs": ">= 0.0.6 < 1",+"stylus": ">= 0.39.1 < 1",+"should": ">= 2.0.2 < 3",+"connect-redis": ">= 1.4.5 < 2",+"marked": ">= 0.2.9 < 1",+"supertest": ">= 0.8.1 < 1"},"keywords": ["express",@@ -66,6 +66,6 @@"test": "make test"},"engines": {-"node": "*"+"node": ">= 0.8.0"}}lib/response.js | 4 ++--1 file changed, 2 insertions(+), 2 deletions(-)
More files changed — see the full commit.