javascript.express.security.audit.express-open-redirect.express-open-redirect

Author
unknown
Download Count*
License
The application redirects to a URL specified by user-supplied input $REQ
that is not validated. This could redirect users to malicious locations. Consider using an allow-list approach to validate URLs, or warn users they are being redirected to a third-party website.
Run Locally
Run in CI
Defintion
rules:
- id: express-open-redirect
message: The application redirects to a URL specified by user-supplied input
`$REQ` that is not validated. This could redirect users to malicious
locations. Consider using an allow-list approach to validate URLs, or warn
users they are being redirected to a third-party website.
metadata:
technology:
- express
references:
- https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html
cwe:
- "CWE-601: URL Redirection to Untrusted Site ('Open Redirect')"
category: security
owasp:
- A01:2021 - Broken Access Control
subcategory:
- vuln
likelihood: HIGH
impact: MEDIUM
confidence: HIGH
license: Commons Clause License Condition v1.0[LGPL-2.1-only]
languages:
- javascript
- typescript
severity: WARNING
options:
taint_unify_mvars: true
symbolic_propagation: true
mode: taint
pattern-sources:
- patterns:
- pattern-either:
- pattern-inside: function ... ($REQ, $RES) {...}
- pattern-inside: function ... ($REQ, $RES, $NEXT) {...}
- patterns:
- pattern-either:
- pattern-inside: $APP.$METHOD(..., function $FUNC($REQ, $RES) {...})
- pattern-inside: $APP.$METHOD(..., function $FUNC($REQ, $RES, $NEXT) {...})
- metavariable-regex:
metavariable: $METHOD
regex: ^(get|post|put|head|delete|options)$
- pattern-either:
- pattern: $REQ.query
- pattern: $REQ.body
- pattern: $REQ.params
- pattern: $REQ.cookies
- pattern: $REQ.headers
- patterns:
- pattern-either:
- pattern-inside: |
({ $REQ }: Request,$RES: Response, $NEXT: NextFunction) =>
{...}
- pattern-inside: |
({ $REQ }: Request,$RES: Response) => {...}
- focus-metavariable: $REQ
- pattern-either:
- pattern: params
- pattern: query
- pattern: cookies
- pattern: headers
- pattern: body
pattern-sinks:
- patterns:
- pattern-either:
- pattern: $RES.redirect("$HTTP"+$REQ. ... .$VALUE)
- pattern: $RES.redirect("$HTTP"+$REQ. ... .$VALUE + $...A)
- pattern: $RES.redirect(`$HTTP${$REQ. ... .$VALUE}...`)
- pattern: $RES.redirect("$HTTP"+$REQ.$VALUE[...])
- pattern: $RES.redirect("$HTTP"+$REQ.$VALUE[...] + $...A)
- pattern: $RES.redirect(`$HTTP${$REQ.$VALUE[...]}...`)
- metavariable-regex:
metavariable: $HTTP
regex: ^https?:\/\/$
- pattern-either:
- pattern: $REQ. ... .$VALUE
- patterns:
- pattern-either:
- pattern: $RES.redirect($REQ. ... .$VALUE)
- pattern: $RES.redirect($REQ. ... .$VALUE + $...A)
- pattern: $RES.redirect(`${$REQ. ... .$VALUE}...`)
- pattern: $REQ. ... .$VALUE
- patterns:
- pattern-either:
- pattern: $RES.redirect($REQ.$VALUE['...'])
- pattern: $RES.redirect($REQ.$VALUE['...'] + $...A)
- pattern: $RES.redirect(`${$REQ.$VALUE['...']}...`)
- pattern: $REQ.$VALUE
- patterns:
- pattern-either:
- pattern-inside: |
$ASSIGN = $REQ. ... .$VALUE
...
- pattern-inside: |
$ASSIGN = $REQ.$VALUE['...']
...
- pattern-inside: |
$ASSIGN = $REQ. ... .$VALUE + $...A
...
- pattern-inside: |
$ASSIGN = $REQ.$VALUE['...'] + $...A
...
- pattern-inside: |
$ASSIGN = `${$REQ. ... .$VALUE}...`
...
- pattern-inside: |
$ASSIGN = `${$REQ.$VALUE['...']}...`
...
- pattern-either:
- pattern: $RES.redirect($ASSIGN)
- pattern: $RES.redirect($ASSIGN + $...FOO)
- pattern: $RES.redirect(`${$ASSIGN}...`)
- pattern: $ASSIGN
Examples
express-open-redirect.js
module.exports.redirect = function (req, res) {
// ok: express-open-redirect
res.redirect(`https://reddit.com/${req.query.url}/fooo`)
// ok: express-open-redirect
res.redirect("https://google.com/"+req.query.url)
// ok: express-open-redirect
res.redirect(config_value.foo+req.query.url)
// ok: express-open-redirect
res.redirect(config_value.foo+req.body.shouldalsonotcatch)
// ok: express-open-redirect
res.redirect(config_value.foo+req)
// ruleid: express-open-redirect
res.redirect(req.body.url)
// ruleid: express-open-redirect
res.redirect(`${req.query.url}/fooo`)
// ruleid: express-open-redirect
res.redirect(req.query.url+config_value.url)
const a = req.body.url
const b = req.body['url']
// ruleid: express-open-redirect
res.redirect(a)
// ruleid: express-open-redirect
res.redirect(`${b}/fooo`)
// ruleid: express-open-redirect
res.redirect(a+config_value.url)
// ok: express-open-redirect
res.redirect(c+a)
// ok: express-open-redirect
res.redirect(`${c}${a}/fooo`)
// ok: express-open-redirect
res.redirect(c+a+config_value.url)
// ok: express-open-redirect
res.redirect(c)
// ok: express-open-redirect
res.redirect(`${c}`)
// ok: express-open-redirect
res.redirect(c+config_value.url)
// ruleid: express-open-redirect
res.redirect(req.body['url'])
// ruleid: express-open-redirect
res.redirect(`${req.body['url']}/fooo`)
// ruleid: express-open-redirect
res.redirect(req.body['url']+config_value.url)
// ruleid: express-open-redirect
res.redirect("https://"+req.body['url'])
// ruleid: express-open-redirect
res.redirect(`https://${req.body['url']}/fooo`)
// ruleid: express-open-redirect
res.redirect("https://"+req.body['url']+config_value.url)
// todo: express-open-redirect
res.redirect("https://google.com"+req.query.url)
}
Short Link: https://sg.run/EpoP