Skip to content

Commit 829a5cc

Browse files
authored
Merge pull request #259 from asger-semmle/open-redirect-expr
Approved by xiemaisi
2 parents 92afcd3 + 9f07b10 commit 829a5cc

File tree

4 files changed

+16
-5
lines changed

4 files changed

+16
-5
lines changed

change-notes/1.19/analysis-javascript.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,6 @@
2727
| Unbound event handler receiver | Fewer false-positive results | This rule now recognizes additional ways class methods can be bound. |
2828
| Remote property injection | Fewer results | The precision of this rule has been revised to "medium". Results are no longer shown on LGTM by default. |
2929
| Missing CSRF middleware | Fewer false-positive results | This rule now recognizes additional CSRF protection middlewares. |
30+
| Server-side URL redirect | More results | This rule now recognizes redirection calls in more cases. |
3031

3132
## Changes to QL libraries

javascript/ql/src/semmle/javascript/security/dataflow/ServerSideUrlRedirect.qll

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ module ServerSideUrlRedirect {
2121
* Holds if this sink may redirect to a non-local URL.
2222
*/
2323
predicate maybeNonLocal() {
24-
exists (Expr prefix | prefix = getAPrefix(this) |
25-
not exists(prefix.getStringValue())
24+
exists (DataFlow::Node prefix | prefix = getAPrefix(this) |
25+
not exists(prefix.asExpr().getStringValue())
2626
or
27-
exists (string prefixVal | prefixVal = prefix.getStringValue() |
27+
exists (string prefixVal | prefixVal = prefix.asExpr().getStringValue() |
2828
// local URLs (i.e., URLs that start with `/` not followed by `\` or `/`,
2929
// or that start with `~/`) are unproblematic
3030
not prefixVal.regexpMatch("/[^\\\\/].*|~/.*") and
@@ -47,12 +47,12 @@ module ServerSideUrlRedirect {
4747
/**
4848
* Gets an expression that may end up being a prefix of the string concatenation `nd`.
4949
*/
50-
private Expr getAPrefix(Sink sink) {
50+
private DataFlow::Node getAPrefix(Sink sink) {
5151
exists (DataFlow::Node prefix |
5252
prefix = prefixCandidate(sink) and
5353
not exists(StringConcatenation::getFirstOperand(prefix)) and
5454
not exists(prefix.getAPredecessor()) and
55-
result = prefix.asExpr()
55+
result = prefix
5656
)
5757
}
5858

javascript/ql/test/query-tests/Security/CWE-601/ServerSideUrlRedirect/ServerSideUrlRedirect.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
| express.js:33:18:33:23 | target | Untrusted URL redirection due to $@. | express.js:27:16:27:34 | req.param("target") | user-provided value |
44
| express.js:35:16:35:21 | target | Untrusted URL redirection due to $@. | express.js:27:16:27:34 | req.param("target") | user-provided value |
55
| express.js:44:16:44:108 | (req.pa ... ntacts" | Untrusted URL redirection due to $@. | express.js:44:69:44:87 | req.param('action') | user-provided value |
6+
| express.js:53:26:53:28 | url | Untrusted URL redirection due to $@. | express.js:48:16:48:28 | req.params[0] | user-provided value |
67
| express.js:78:16:78:43 | `${req. ... )}/foo` | Untrusted URL redirection due to $@. | express.js:78:19:78:37 | req.param("target") | user-provided value |
78
| express.js:94:18:94:23 | target | Untrusted URL redirection due to $@. | express.js:87:16:87:34 | req.param("target") | user-provided value |
89
| express.js:101:16:101:21 | target | Untrusted URL redirection due to $@. | express.js:87:16:87:34 | req.param("target") | user-provided value |

javascript/ql/test/query-tests/Security/CWE-601/ServerSideUrlRedirect/express.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,3 +121,12 @@ app.get('/array/join', function(req, res) {
121121
// BAD: request input becomes before query string
122122
res.redirect([req.query.page, '?section=', req.query.section].join(''));
123123
});
124+
125+
function sendUserToUrl(res, nextUrl) {
126+
// BAD: value comes from query parameter
127+
res.redrect(nextUrl);
128+
}
129+
130+
app.get('/call', function(req, res) {
131+
sendUserToUrl(res, req.query.nextUrl);
132+
});

0 commit comments

Comments
 (0)