contrib.nodejsscan.open_redirect.express_open_redirect

Author
99
Download Count*
License
Untrusted user input in redirect() can result in Open Redirect vulnerability.
Run Locally
Run in CI
Defintion
rules:
- id: express_open_redirect
patterns:
- pattern-either:
- pattern-inside: function ($REQ, $RES, ...) {...}
- pattern-inside: function $FUNC($REQ, $RES, ...) {...}
- pattern-inside: $X = function $FUNC($REQ, $RES, ...) {...}
- pattern-inside: var $X = function $FUNC($REQ, $RES, ...) {...};
- pattern-inside: $APP.$METHOD(..., function $FUNC($REQ, $RES, ...) {...})
- pattern-either:
- pattern: |
$X.redirect(..., <... $REQ.$QUERY ...>, ...)
- pattern: |
$X.redirect(..., <... $REQ.$QUERY.$FOO ...>, ...)
- pattern: |
$INP = <... $REQ.$QUERY ...>;
...
$X.redirect(..., <... $INP ...>, ...);
- pattern: |
$INP = <... $REQ.$QUERY.$FOO ...>;
...
$X.redirect(..., <... $INP ...>, ...);
message: Untrusted user input in redirect() can result in Open Redirect
vulnerability.
languages:
- javascript
severity: ERROR
metadata:
owasp: A01:2017 - Injection
cwe: "CWE-601: URL Redirection to Untrusted Site ('Open Redirect')"
license: Commons Clause License Condition v1.0[LGPL-2.1-only]
Examples
open_redirect.js
const express = require('express');
const router = express.Router()
router.use((req, res, next) => {
if (req.method === 'POST') {
console.log(JSON.stringify(req.session.data, null, 2))
}
next()
})
router.post('/sprint18b/frequency', (req, res) => {
res.redirect('/sprint18b/payment') //GOOD
});
var express = require('express');
var app = express();
app.get('/some/path', function (req, res) {
// BAD: a request parameter is incorporated without validation into a URL redirect
// ruleid:express_open_redirect
res.redirect(302, req.param("target"));
});
app.get('/some/path1', function (req, res) {
// BAD: a request parameter is incorporated without validation into a URL redirect
// ruleid:express_open_redirect
res.redirect(300, req.param);
});
app.get('/some/path2', function (req, res) {
// BAD: a request parameter is incorporated without validation into a URL redirect
// ruleid:express_open_redirect
res.redirect(req.param["target"]);
});
app.get('/some/path3', function (req, res) {
// BAD: a request parameter is incorporated without validation into a URL redirect
// ruleid:express_open_redirect
res.redirect(req.body.url);
});
app.get('/some/path4', function (req, res) {
// BAD subdomain control
// ruleid:express_open_redirect
res.redirect("sdcssf" + req.param("target"));
});
app.get('/some/path5', function (req, res) {
// BAD: a request parameter is incorporated without validation into a URL redirect
// ruleid:express_open_redirect
res.redirect(req.param("target") + "/asdad");
});
app.all(function (req, res) {
// BAD: a request parameter is incorporated without validation into a URL redirect
// ruleid:express_open_redirect2
res.header("Location", req.param["target"]);
});
app.all(function (req, res) {
// BAD: a request parameter is incorporated without validation into a URL redirect
// ruleid:express_open_redirect2
res.header('Location', req.param("foo"));
});
app.all(function (req, res) {
// ruleid:express_open_redirect2
res.writeHead(200, { location: 'foo \rinvalid: bar' + req.foo + 'asdadasd', foo: bar });
});
app.all(function (req, res) {
// ruleid:express_open_redirect2
res.writeHead(200, { 'location': req.foo });
});
app.all(function (req, res) {
// BAD: a request parameter is incorporated without validation into a URL redirect
// ruleid:express_open_redirect2
res.header('location', req.param("bar"));
});
app.get('/some/path', function (req, res) {
// ruleid:express_open_redirect
var target = req.param("target");
// BAD: sanitization doesn't apply here
res.redirect(target);
});
app.get('/foo', function (req, res) {
// BAD: may be a global redirection
// ruleid:express_open_redirect
res.redirect((req.param('action') && req.param('action') != "") ? req.param('action') : "/google_contacts")
});
app.get('/yet/another/path', function (req, res) {
// BAD: a request parameter is incorporated without validation into a URL redirect
// ruleid:express_open_redirect
res.redirect(`${req.param("target")}/foo`);
});
app.get('/array/join', function (req, res) {
// BAD: request input becomes before query string
// ruleid:express_open_redirect
res.redirect([req.query.page, '?section=', req.query.section].join(''));
});
app.get('/call', function (req, res) {
sendUserToUrl(res, req.query.nextUrl);
});
function sendUserToUrl(res, nextUrl) {
// BAD: value comes from query parameter
res.redrect(nextUrl);
}
app.get('/redirect/:user', function (req, res) {
// ruleid:express_open_redirect
res.redirect('/' + req.params.user); // BAD - could go to //evil.com
// ruleid:express_open_redirect
res.redirect('//' + req.params.user); // BAD - could go to //evil.com
// ruleid:express_open_redirect
res.redirect('u' + req.params.user); // BAD - could go to u.evil.com
// ruleid:express_open_redirect
res.redirect('Fan999' + req.params.user); // BAD - could go to Fan999.evil.com
// ruleid:express_open_redirect
res.redirect('/' + ('/u' + req.params.user)); // BAD - could go to //u.evil.com,
//do not trigger
res.redirect('/' + foo)
});
Short Link: https://sg.run/PJn3