diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/ServerSideUrlRedirectQuery.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/ServerSideUrlRedirectQuery.qll index 7f16f7f49dd..94614094cb1 100644 --- a/javascript/ql/lib/semmle/javascript/security/dataflow/ServerSideUrlRedirectQuery.qll +++ b/javascript/ql/lib/semmle/javascript/security/dataflow/ServerSideUrlRedirectQuery.qll @@ -15,7 +15,32 @@ import ServerSideUrlRedirectCustomizations::ServerSideUrlRedirect /** * A taint-tracking configuration for reasoning about unvalidated URL redirections. */ -class Configuration extends TaintTracking::Configuration { +module ServerSideUrlRedirectConfig implements DataFlow::ConfigSig { + predicate isSource(DataFlow::Node source) { source instanceof Source } + + predicate isSink(DataFlow::Node sink) { sink instanceof Sink } + + predicate isBarrier(DataFlow::Node node) { node instanceof Sanitizer } + + predicate isBarrierOut(DataFlow::Node node) { hostnameSanitizingPrefixEdge(node, _) } + + predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) { + exists(HtmlSanitizerCall call | + pred = call.getInput() and + succ = call + ) + } +} + +/** + * Taint-tracking for reasoning about unvalidated URL redirections. + */ +module ServerSideUrlRedirectFlow = TaintTracking::Global; + +/** + * DEPRECATED. Use the `ServerSideUrlRedirectFlow` module instead. + */ +deprecated class Configuration extends TaintTracking::Configuration { Configuration() { this = "ServerSideUrlRedirect" } override predicate isSource(DataFlow::Node source) { source instanceof Source } @@ -27,7 +52,9 @@ class Configuration extends TaintTracking::Configuration { node instanceof Sanitizer } - override predicate isSanitizerOut(DataFlow::Node node) { hostnameSanitizingPrefixEdge(node, _) } + override predicate isSanitizerOut(DataFlow::Node node) { + ServerSideUrlRedirectConfig::isBarrierOut(node) + } override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) { guard instanceof LocalUrlSanitizingGuard or @@ -35,10 +62,7 @@ class Configuration extends TaintTracking::Configuration { } override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { - exists(HtmlSanitizerCall call | - pred = call.getInput() and - succ = call - ) + ServerSideUrlRedirectConfig::isAdditionalFlowStep(pred, succ) } } @@ -49,8 +73,10 @@ class Configuration extends TaintTracking::Configuration { class LocalUrlSanitizingGuard extends TaintTracking::SanitizerGuardNode, DataFlow::CallNode { LocalUrlSanitizingGuard() { this.getCalleeName().regexpMatch("(?i)(is_?)?local_?url") } - override predicate sanitizes(boolean outcome, Expr e) { - // `isLocalUrl(e)` sanitizes `e` if it evaluates to `true` + override predicate sanitizes(boolean outcome, Expr e) { this.blocksExpr(outcome, e) } + + /** Holds if this node blocks flow through `e`, provided it evaluates to `outcome`. */ + predicate blocksExpr(boolean outcome, Expr e) { this.getAnArgument().asExpr() = e and outcome = true } diff --git a/javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.ql b/javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.ql index 76402706586..e3bc53ec436 100644 --- a/javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.ql +++ b/javascript/ql/src/Security/CWE-601/ServerSideUrlRedirect.ql @@ -13,9 +13,9 @@ import javascript import semmle.javascript.security.dataflow.ServerSideUrlRedirectQuery -import DataFlow::PathGraph +import ServerSideUrlRedirectFlow::PathGraph -from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink -where cfg.hasFlowPath(source, sink) +from ServerSideUrlRedirectFlow::PathNode source, ServerSideUrlRedirectFlow::PathNode sink +where ServerSideUrlRedirectFlow::flowPath(source, sink) select sink.getNode(), source, sink, "Untrusted URL redirection depends on a $@.", source.getNode(), "user-provided value" diff --git a/javascript/ql/test/query-tests/Security/CWE-601/ServerSideUrlRedirect/ServerSideUrlRedirect.expected b/javascript/ql/test/query-tests/Security/CWE-601/ServerSideUrlRedirect/ServerSideUrlRedirect.expected index c03f57e7dd5..4497676ff2e 100644 --- a/javascript/ql/test/query-tests/Security/CWE-601/ServerSideUrlRedirect/ServerSideUrlRedirect.expected +++ b/javascript/ql/test/query-tests/Security/CWE-601/ServerSideUrlRedirect/ServerSideUrlRedirect.expected @@ -1,223 +1,120 @@ -nodes -| ServerSideUrlRedirect.js:5:16:5:34 | req.query["target"] | -| ServerSideUrlRedirect.js:5:16:5:34 | req.query["target"] | -| ServerSideUrlRedirect.js:5:16:5:34 | req.query["target"] | -| express.js:7:16:7:34 | req.param("target") | -| express.js:7:16:7:34 | req.param("target") | -| express.js:7:16:7:34 | req.param("target") | -| express.js:12:26:12:44 | req.param("target") | -| express.js:12:26:12:44 | req.param("target") | -| express.js:12:26:12:44 | req.param("target") | -| express.js:27:7:27:34 | target | -| express.js:27:16:27:34 | req.param("target") | -| express.js:27:16:27:34 | req.param("target") | -| express.js:33:18:33:23 | target | -| express.js:33:18:33:23 | target | -| express.js:35:16:35:21 | target | -| express.js:35:16:35:21 | target | -| express.js:40:16:40:108 | (req.pa ... ntacts" | -| express.js:40:16:40:108 | (req.pa ... ntacts" | -| express.js:40:69:40:87 | req.param('action') | -| express.js:40:69:40:87 | req.param('action') | -| express.js:74:16:74:43 | `${req. ... )}/foo` | -| express.js:74:16:74:43 | `${req. ... )}/foo` | -| express.js:74:19:74:37 | req.param("target") | -| express.js:74:19:74:37 | req.param("target") | -| express.js:83:7:83:34 | target | -| express.js:83:16:83:34 | req.param("target") | -| express.js:83:16:83:34 | req.param("target") | -| express.js:90:18:90:23 | target | -| express.js:90:18:90:23 | target | -| express.js:97:16:97:21 | target | -| express.js:97:16:97:21 | target | -| express.js:118:16:118:63 | [req.qu ... ection] | -| express.js:118:16:118:72 | [req.qu ... oin('') | -| express.js:118:16:118:72 | [req.qu ... oin('') | -| express.js:118:17:118:30 | req.query.page | -| express.js:118:17:118:30 | req.query.page | -| express.js:134:16:134:36 | '/' + r ... ms.user | -| express.js:134:16:134:36 | '/' + r ... ms.user | -| express.js:134:22:134:36 | req.params.user | -| express.js:134:22:134:36 | req.params.user | -| express.js:135:16:135:37 | '//' + ... ms.user | -| express.js:135:16:135:37 | '//' + ... ms.user | -| express.js:135:23:135:37 | req.params.user | -| express.js:135:23:135:37 | req.params.user | -| express.js:136:16:136:36 | 'u' + r ... ms.user | -| express.js:136:16:136:36 | 'u' + r ... ms.user | -| express.js:136:22:136:36 | req.params.user | -| express.js:136:22:136:36 | req.params.user | -| express.js:143:16:143:28 | req.query.foo | -| express.js:143:16:143:28 | req.query.foo | -| express.js:143:16:143:28 | req.query.foo | -| express.js:146:16:146:24 | query.foo | -| express.js:146:16:146:24 | query.foo | -| express.js:146:16:146:24 | query.foo | -| express.js:150:7:150:34 | target | -| express.js:150:16:150:34 | req.param("target") | -| express.js:150:16:150:34 | req.param("target") | -| express.js:155:18:155:23 | target | -| express.js:155:18:155:23 | target | -| express.js:160:18:160:23 | target | -| express.js:160:18:160:23 | target | -| express.js:164:7:164:54 | myThing | -| express.js:164:17:164:41 | JSON.st ... .query) | -| express.js:164:17:164:54 | JSON.st ... (1, -1) | -| express.js:164:32:164:40 | req.query | -| express.js:164:32:164:40 | req.query | -| express.js:165:16:165:22 | myThing | -| express.js:165:16:165:22 | myThing | -| koa.js:6:6:6:27 | url | -| koa.js:6:12:6:27 | ctx.query.target | -| koa.js:6:12:6:27 | ctx.query.target | -| koa.js:7:15:7:17 | url | -| koa.js:7:15:7:17 | url | -| koa.js:8:15:8:26 | `${url}${x}` | -| koa.js:8:15:8:26 | `${url}${x}` | -| koa.js:8:18:8:20 | url | -| koa.js:14:16:14:18 | url | -| koa.js:14:16:14:18 | url | -| koa.js:20:16:20:18 | url | -| koa.js:20:16:20:18 | url | -| next.ts:11:31:11:38 | req.body | -| next.ts:11:31:11:38 | req.body | -| next.ts:11:31:11:50 | req.body.callbackUrl | -| next.ts:11:31:11:50 | req.body.callbackUrl | -| node.js:5:7:5:52 | target | -| node.js:5:16:5:39 | url.par ... , true) | -| node.js:5:16:5:45 | url.par ... ).query | -| node.js:5:16:5:52 | url.par ... .target | -| node.js:5:26:5:32 | req.url | -| node.js:5:26:5:32 | req.url | -| node.js:6:34:6:39 | target | -| node.js:6:34:6:39 | target | -| node.js:10:7:10:52 | target | -| node.js:10:16:10:39 | url.par ... , true) | -| node.js:10:16:10:45 | url.par ... ).query | -| node.js:10:16:10:52 | url.par ... .target | -| node.js:10:26:10:32 | req.url | -| node.js:10:26:10:32 | req.url | -| node.js:14:34:14:45 | '/' + target | -| node.js:14:34:14:45 | '/' + target | -| node.js:14:40:14:45 | target | -| node.js:28:7:28:52 | target | -| node.js:28:16:28:39 | url.par ... , true) | -| node.js:28:16:28:45 | url.par ... ).query | -| node.js:28:16:28:52 | url.par ... .target | -| node.js:28:26:28:32 | req.url | -| node.js:28:26:28:32 | req.url | -| node.js:31:34:31:39 | target | -| node.js:31:34:31:55 | target ... =" + me | -| node.js:31:34:31:55 | target ... =" + me | -| react-native.js:7:7:7:33 | tainted | -| react-native.js:7:17:7:33 | req.param("code") | -| react-native.js:7:17:7:33 | req.param("code") | -| react-native.js:8:17:8:23 | tainted | -| react-native.js:8:17:8:23 | tainted | -| react-native.js:9:26:9:32 | tainted | -| react-native.js:9:26:9:32 | tainted | edges -| ServerSideUrlRedirect.js:5:16:5:34 | req.query["target"] | ServerSideUrlRedirect.js:5:16:5:34 | req.query["target"] | -| express.js:7:16:7:34 | req.param("target") | express.js:7:16:7:34 | req.param("target") | -| express.js:12:26:12:44 | req.param("target") | express.js:12:26:12:44 | req.param("target") | -| express.js:27:7:27:34 | target | express.js:33:18:33:23 | target | +| ServerSideUrlRedirectGood2.js:16:7:16:34 | target | ServerSideUrlRedirectGood2.js:18:18:18:23 | target | +| ServerSideUrlRedirectGood2.js:16:16:16:34 | req.query["target"] | ServerSideUrlRedirectGood2.js:16:7:16:34 | target | +| express.js:27:7:27:34 | target | express.js:30:18:30:23 | target | | express.js:27:7:27:34 | target | express.js:33:18:33:23 | target | | express.js:27:7:27:34 | target | express.js:35:16:35:21 | target | -| express.js:27:7:27:34 | target | express.js:35:16:35:21 | target | -| express.js:27:16:27:34 | req.param("target") | express.js:27:7:27:34 | target | | express.js:27:16:27:34 | req.param("target") | express.js:27:7:27:34 | target | | express.js:40:69:40:87 | req.param('action') | express.js:40:16:40:108 | (req.pa ... ntacts" | -| express.js:40:69:40:87 | req.param('action') | express.js:40:16:40:108 | (req.pa ... ntacts" | -| express.js:40:69:40:87 | req.param('action') | express.js:40:16:40:108 | (req.pa ... ntacts" | -| express.js:40:69:40:87 | req.param('action') | express.js:40:16:40:108 | (req.pa ... ntacts" | -| express.js:74:19:74:37 | req.param("target") | express.js:74:16:74:43 | `${req. ... )}/foo` | -| express.js:74:19:74:37 | req.param("target") | express.js:74:16:74:43 | `${req. ... )}/foo` | -| express.js:74:19:74:37 | req.param("target") | express.js:74:16:74:43 | `${req. ... )}/foo` | | express.js:74:19:74:37 | req.param("target") | express.js:74:16:74:43 | `${req. ... )}/foo` | | express.js:83:7:83:34 | target | express.js:90:18:90:23 | target | -| express.js:83:7:83:34 | target | express.js:90:18:90:23 | target | -| express.js:83:7:83:34 | target | express.js:97:16:97:21 | target | | express.js:83:7:83:34 | target | express.js:97:16:97:21 | target | | express.js:83:16:83:34 | req.param("target") | express.js:83:7:83:34 | target | -| express.js:83:16:83:34 | req.param("target") | express.js:83:7:83:34 | target | -| express.js:118:16:118:63 | [req.qu ... ection] | express.js:118:16:118:72 | [req.qu ... oin('') | -| express.js:118:16:118:63 | [req.qu ... ection] | express.js:118:16:118:72 | [req.qu ... oin('') | -| express.js:118:17:118:30 | req.query.page | express.js:118:16:118:63 | [req.qu ... ection] | -| express.js:118:17:118:30 | req.query.page | express.js:118:16:118:63 | [req.qu ... ection] | -| express.js:134:22:134:36 | req.params.user | express.js:134:16:134:36 | '/' + r ... ms.user | -| express.js:134:22:134:36 | req.params.user | express.js:134:16:134:36 | '/' + r ... ms.user | -| express.js:134:22:134:36 | req.params.user | express.js:134:16:134:36 | '/' + r ... ms.user | +| express.js:118:17:118:30 | req.query.page | express.js:118:16:118:72 | [req.qu ... oin('') | | express.js:134:22:134:36 | req.params.user | express.js:134:16:134:36 | '/' + r ... ms.user | | express.js:135:23:135:37 | req.params.user | express.js:135:16:135:37 | '//' + ... ms.user | -| express.js:135:23:135:37 | req.params.user | express.js:135:16:135:37 | '//' + ... ms.user | -| express.js:135:23:135:37 | req.params.user | express.js:135:16:135:37 | '//' + ... ms.user | -| express.js:135:23:135:37 | req.params.user | express.js:135:16:135:37 | '//' + ... ms.user | | express.js:136:22:136:36 | req.params.user | express.js:136:16:136:36 | 'u' + r ... ms.user | -| express.js:136:22:136:36 | req.params.user | express.js:136:16:136:36 | 'u' + r ... ms.user | -| express.js:136:22:136:36 | req.params.user | express.js:136:16:136:36 | 'u' + r ... ms.user | -| express.js:136:22:136:36 | req.params.user | express.js:136:16:136:36 | 'u' + r ... ms.user | -| express.js:143:16:143:28 | req.query.foo | express.js:143:16:143:28 | req.query.foo | -| express.js:146:16:146:24 | query.foo | express.js:146:16:146:24 | query.foo | -| express.js:150:7:150:34 | target | express.js:155:18:155:23 | target | | express.js:150:7:150:34 | target | express.js:155:18:155:23 | target | | express.js:150:7:150:34 | target | express.js:160:18:160:23 | target | -| express.js:150:7:150:34 | target | express.js:160:18:160:23 | target | | express.js:150:16:150:34 | req.param("target") | express.js:150:7:150:34 | target | -| express.js:150:16:150:34 | req.param("target") | express.js:150:7:150:34 | target | -| express.js:164:7:164:54 | myThing | express.js:165:16:165:22 | myThing | | express.js:164:7:164:54 | myThing | express.js:165:16:165:22 | myThing | | express.js:164:17:164:41 | JSON.st ... .query) | express.js:164:17:164:54 | JSON.st ... (1, -1) | | express.js:164:17:164:54 | JSON.st ... (1, -1) | express.js:164:7:164:54 | myThing | | express.js:164:32:164:40 | req.query | express.js:164:17:164:41 | JSON.st ... .query) | -| express.js:164:32:164:40 | req.query | express.js:164:17:164:41 | JSON.st ... .query) | -| koa.js:6:6:6:27 | url | koa.js:7:15:7:17 | url | | koa.js:6:6:6:27 | url | koa.js:7:15:7:17 | url | | koa.js:6:6:6:27 | url | koa.js:8:18:8:20 | url | | koa.js:6:6:6:27 | url | koa.js:14:16:14:18 | url | -| koa.js:6:6:6:27 | url | koa.js:14:16:14:18 | url | -| koa.js:6:6:6:27 | url | koa.js:20:16:20:18 | url | | koa.js:6:6:6:27 | url | koa.js:20:16:20:18 | url | | koa.js:6:12:6:27 | ctx.query.target | koa.js:6:6:6:27 | url | -| koa.js:6:12:6:27 | ctx.query.target | koa.js:6:6:6:27 | url | -| koa.js:8:18:8:20 | url | koa.js:8:15:8:26 | `${url}${x}` | | koa.js:8:18:8:20 | url | koa.js:8:15:8:26 | `${url}${x}` | | next.ts:11:31:11:38 | req.body | next.ts:11:31:11:50 | req.body.callbackUrl | -| next.ts:11:31:11:38 | req.body | next.ts:11:31:11:50 | req.body.callbackUrl | -| next.ts:11:31:11:38 | req.body | next.ts:11:31:11:50 | req.body.callbackUrl | -| next.ts:11:31:11:38 | req.body | next.ts:11:31:11:50 | req.body.callbackUrl | | node.js:5:7:5:52 | target | node.js:6:34:6:39 | target | -| node.js:5:7:5:52 | target | node.js:6:34:6:39 | target | -| node.js:5:16:5:39 | url.par ... , true) | node.js:5:16:5:45 | url.par ... ).query | -| node.js:5:16:5:45 | url.par ... ).query | node.js:5:16:5:52 | url.par ... .target | -| node.js:5:16:5:52 | url.par ... .target | node.js:5:7:5:52 | target | -| node.js:5:26:5:32 | req.url | node.js:5:16:5:39 | url.par ... , true) | +| node.js:5:16:5:39 | url.par ... , true) | node.js:5:7:5:52 | target | | node.js:5:26:5:32 | req.url | node.js:5:16:5:39 | url.par ... , true) | | node.js:10:7:10:52 | target | node.js:14:40:14:45 | target | -| node.js:10:16:10:39 | url.par ... , true) | node.js:10:16:10:45 | url.par ... ).query | -| node.js:10:16:10:45 | url.par ... ).query | node.js:10:16:10:52 | url.par ... .target | -| node.js:10:16:10:52 | url.par ... .target | node.js:10:7:10:52 | target | +| node.js:10:16:10:39 | url.par ... , true) | node.js:10:7:10:52 | target | | node.js:10:26:10:32 | req.url | node.js:10:16:10:39 | url.par ... , true) | -| node.js:10:26:10:32 | req.url | node.js:10:16:10:39 | url.par ... , true) | -| node.js:14:40:14:45 | target | node.js:14:34:14:45 | '/' + target | | node.js:14:40:14:45 | target | node.js:14:34:14:45 | '/' + target | | node.js:28:7:28:52 | target | node.js:31:34:31:39 | target | -| node.js:28:16:28:39 | url.par ... , true) | node.js:28:16:28:45 | url.par ... ).query | -| node.js:28:16:28:45 | url.par ... ).query | node.js:28:16:28:52 | url.par ... .target | -| node.js:28:16:28:52 | url.par ... .target | node.js:28:7:28:52 | target | -| node.js:28:26:28:32 | req.url | node.js:28:16:28:39 | url.par ... , true) | +| node.js:28:16:28:39 | url.par ... , true) | node.js:28:7:28:52 | target | | node.js:28:26:28:32 | req.url | node.js:28:16:28:39 | url.par ... , true) | | node.js:31:34:31:39 | target | node.js:31:34:31:55 | target ... =" + me | -| node.js:31:34:31:39 | target | node.js:31:34:31:55 | target ... =" + me | -| react-native.js:7:7:7:33 | tainted | react-native.js:8:17:8:23 | tainted | | react-native.js:7:7:7:33 | tainted | react-native.js:8:17:8:23 | tainted | | react-native.js:7:7:7:33 | tainted | react-native.js:9:26:9:32 | tainted | -| react-native.js:7:7:7:33 | tainted | react-native.js:9:26:9:32 | tainted | -| react-native.js:7:17:7:33 | req.param("code") | react-native.js:7:7:7:33 | tainted | | react-native.js:7:17:7:33 | req.param("code") | react-native.js:7:7:7:33 | tainted | +nodes +| ServerSideUrlRedirect.js:5:16:5:34 | req.query["target"] | semmle.label | req.query["target"] | +| ServerSideUrlRedirectGood2.js:16:7:16:34 | target | semmle.label | target | +| ServerSideUrlRedirectGood2.js:16:16:16:34 | req.query["target"] | semmle.label | req.query["target"] | +| ServerSideUrlRedirectGood2.js:18:18:18:23 | target | semmle.label | target | +| express.js:7:16:7:34 | req.param("target") | semmle.label | req.param("target") | +| express.js:12:26:12:44 | req.param("target") | semmle.label | req.param("target") | +| express.js:27:7:27:34 | target | semmle.label | target | +| express.js:27:16:27:34 | req.param("target") | semmle.label | req.param("target") | +| express.js:30:18:30:23 | target | semmle.label | target | +| express.js:33:18:33:23 | target | semmle.label | target | +| express.js:35:16:35:21 | target | semmle.label | target | +| express.js:40:16:40:108 | (req.pa ... ntacts" | semmle.label | (req.pa ... ntacts" | +| express.js:40:69:40:87 | req.param('action') | semmle.label | req.param('action') | +| express.js:74:16:74:43 | `${req. ... )}/foo` | semmle.label | `${req. ... )}/foo` | +| express.js:74:19:74:37 | req.param("target") | semmle.label | req.param("target") | +| express.js:83:7:83:34 | target | semmle.label | target | +| express.js:83:16:83:34 | req.param("target") | semmle.label | req.param("target") | +| express.js:90:18:90:23 | target | semmle.label | target | +| express.js:97:16:97:21 | target | semmle.label | target | +| express.js:118:16:118:72 | [req.qu ... oin('') | semmle.label | [req.qu ... oin('') | +| express.js:118:17:118:30 | req.query.page | semmle.label | req.query.page | +| express.js:134:16:134:36 | '/' + r ... ms.user | semmle.label | '/' + r ... ms.user | +| express.js:134:22:134:36 | req.params.user | semmle.label | req.params.user | +| express.js:135:16:135:37 | '//' + ... ms.user | semmle.label | '//' + ... ms.user | +| express.js:135:23:135:37 | req.params.user | semmle.label | req.params.user | +| express.js:136:16:136:36 | 'u' + r ... ms.user | semmle.label | 'u' + r ... ms.user | +| express.js:136:22:136:36 | req.params.user | semmle.label | req.params.user | +| express.js:143:16:143:28 | req.query.foo | semmle.label | req.query.foo | +| express.js:146:16:146:24 | query.foo | semmle.label | query.foo | +| express.js:150:7:150:34 | target | semmle.label | target | +| express.js:150:16:150:34 | req.param("target") | semmle.label | req.param("target") | +| express.js:155:18:155:23 | target | semmle.label | target | +| express.js:160:18:160:23 | target | semmle.label | target | +| express.js:164:7:164:54 | myThing | semmle.label | myThing | +| express.js:164:17:164:41 | JSON.st ... .query) | semmle.label | JSON.st ... .query) | +| express.js:164:17:164:54 | JSON.st ... (1, -1) | semmle.label | JSON.st ... (1, -1) | +| express.js:164:32:164:40 | req.query | semmle.label | req.query | +| express.js:165:16:165:22 | myThing | semmle.label | myThing | +| koa.js:6:6:6:27 | url | semmle.label | url | +| koa.js:6:12:6:27 | ctx.query.target | semmle.label | ctx.query.target | +| koa.js:7:15:7:17 | url | semmle.label | url | +| koa.js:8:15:8:26 | `${url}${x}` | semmle.label | `${url}${x}` | +| koa.js:8:18:8:20 | url | semmle.label | url | +| koa.js:14:16:14:18 | url | semmle.label | url | +| koa.js:20:16:20:18 | url | semmle.label | url | +| next.ts:11:31:11:38 | req.body | semmle.label | req.body | +| next.ts:11:31:11:50 | req.body.callbackUrl | semmle.label | req.body.callbackUrl | +| node.js:5:7:5:52 | target | semmle.label | target | +| node.js:5:16:5:39 | url.par ... , true) | semmle.label | url.par ... , true) | +| node.js:5:26:5:32 | req.url | semmle.label | req.url | +| node.js:6:34:6:39 | target | semmle.label | target | +| node.js:10:7:10:52 | target | semmle.label | target | +| node.js:10:16:10:39 | url.par ... , true) | semmle.label | url.par ... , true) | +| node.js:10:26:10:32 | req.url | semmle.label | req.url | +| node.js:14:34:14:45 | '/' + target | semmle.label | '/' + target | +| node.js:14:40:14:45 | target | semmle.label | target | +| node.js:28:7:28:52 | target | semmle.label | target | +| node.js:28:16:28:39 | url.par ... , true) | semmle.label | url.par ... , true) | +| node.js:28:26:28:32 | req.url | semmle.label | req.url | +| node.js:31:34:31:39 | target | semmle.label | target | +| node.js:31:34:31:55 | target ... =" + me | semmle.label | target ... =" + me | +| react-native.js:7:7:7:33 | tainted | semmle.label | tainted | +| react-native.js:7:17:7:33 | req.param("code") | semmle.label | req.param("code") | +| react-native.js:8:17:8:23 | tainted | semmle.label | tainted | +| react-native.js:9:26:9:32 | tainted | semmle.label | tainted | +subpaths #select | ServerSideUrlRedirect.js:5:16:5:34 | req.query["target"] | ServerSideUrlRedirect.js:5:16:5:34 | req.query["target"] | ServerSideUrlRedirect.js:5:16:5:34 | req.query["target"] | Untrusted URL redirection depends on a $@. | ServerSideUrlRedirect.js:5:16:5:34 | req.query["target"] | user-provided value | +| ServerSideUrlRedirectGood2.js:18:18:18:23 | target | ServerSideUrlRedirectGood2.js:16:16:16:34 | req.query["target"] | ServerSideUrlRedirectGood2.js:18:18:18:23 | target | Untrusted URL redirection depends on a $@. | ServerSideUrlRedirectGood2.js:16:16:16:34 | req.query["target"] | user-provided value | | express.js:7:16:7:34 | req.param("target") | express.js:7:16:7:34 | req.param("target") | express.js:7:16:7:34 | req.param("target") | Untrusted URL redirection depends on a $@. | express.js:7:16:7:34 | req.param("target") | user-provided value | | express.js:12:26:12:44 | req.param("target") | express.js:12:26:12:44 | req.param("target") | express.js:12:26:12:44 | req.param("target") | Untrusted URL redirection depends on a $@. | express.js:12:26:12:44 | req.param("target") | user-provided value | +| express.js:30:18:30:23 | target | express.js:27:16:27:34 | req.param("target") | express.js:30:18:30:23 | target | Untrusted URL redirection depends on a $@. | express.js:27:16:27:34 | req.param("target") | user-provided value | | express.js:33:18:33:23 | target | express.js:27:16:27:34 | req.param("target") | express.js:33:18:33:23 | target | Untrusted URL redirection depends on a $@. | express.js:27:16:27:34 | req.param("target") | user-provided value | | express.js:35:16:35:21 | target | express.js:27:16:27:34 | req.param("target") | express.js:35:16:35:21 | target | Untrusted URL redirection depends on a $@. | express.js:27:16:27:34 | req.param("target") | user-provided value | | express.js:40:16:40:108 | (req.pa ... ntacts" | express.js:40:69:40:87 | req.param('action') | express.js:40:16:40:108 | (req.pa ... ntacts" | Untrusted URL redirection depends on a $@. | express.js:40:69:40:87 | req.param('action') | user-provided value |