Skip to content

Commit 199990f

Browse files
author
Max Schaefer
committed
JavaScript: Add WebView-related taint sinks for CodeInjection, DomBasedXss and ServerSideUrlRedirect.
1 parent 3ce82af commit 199990f

File tree

10 files changed

+74
-0
lines changed

10 files changed

+74
-0
lines changed

javascript/ql/src/javascript.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ import semmle.javascript.frameworks.HttpFrameworks
6262
import semmle.javascript.frameworks.NoSQL
6363
import semmle.javascript.frameworks.PkgCloud
6464
import semmle.javascript.frameworks.React
65+
import semmle.javascript.frameworks.ReactNative
6566
import semmle.javascript.frameworks.Request
6667
import semmle.javascript.frameworks.SQL
6768
import semmle.javascript.frameworks.UriLibraries

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,21 @@ module CodeInjection {
115115
)
116116
}
117117
}
118+
119+
/**
120+
* An expression which is injected as JavaScript into a React Native `WebView`.
121+
*/
122+
class WebViewInjectedJavaScriptSink extends Sink {
123+
WebViewInjectedJavaScriptSink() {
124+
exists (ReactNative::WebViewElement webView |
125+
// `injectedJavaScript` property of React Native `WebView`
126+
this = webView.getAPropertyWrite("injectedJavaScript").getRhs()
127+
or
128+
// argument to `injectJavascript` method of React Native `WebView`
129+
this = webView.getAMethodCall("injectJavaScript").getArgument(0)
130+
)
131+
}
132+
}
118133
}
119134

120135
/** DEPRECATED: Use `CodeInjection::Source` instead. */

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,13 @@ module DomBasedXss {
117117
pw.interpretsValueAsHTML() and
118118
this = DataFlow::valueNode(pw.getRhs())
119119
)
120+
or
121+
// `html` or `source.html` properties of React Native `WebView`
122+
exists (ReactNative::WebViewElement webView, DataFlow::SourceNode source |
123+
source = webView or
124+
source = webView.getAPropertyWrite("source").getRhs().getALocalSource() |
125+
this = source.getAPropertyWrite("html").getRhs()
126+
)
120127
}
121128
}
122129

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,20 @@ module ServerSideUrlRedirect {
140140
outcome = true
141141
}
142142
}
143+
144+
/**
145+
* A URL attribute for a React Native `WebView`.
146+
*/
147+
class WebViewUrlSink extends Sink {
148+
WebViewUrlSink() {
149+
// `url` or `source.uri` properties of React Native `WebView`
150+
exists (ReactNative::WebViewElement webView, DataFlow::SourceNode source, string prop |
151+
source = webView and prop = "url" or
152+
source = webView.getAPropertyWrite("source").getRhs().getALocalSource() and prop = "uri" |
153+
this = source.getAPropertyWrite(prop).getRhs()
154+
)
155+
}
156+
}
143157
}
144158

145159
/** DEPRECATED: Use `ServerSideUrlRedirect::Source` instead. */

javascript/ql/test/query-tests/Security/CWE-079/Xss.expected

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
| jquery.js:4:5:4:11 | tainted | Cross-site scripting vulnerability due to $@. | jquery.js:2:17:2:33 | document.location | user-provided value |
22
| jquery.js:7:5:7:34 | "<div i ... + "\\">" | Cross-site scripting vulnerability due to $@. | jquery.js:2:17:2:33 | document.location | user-provided value |
33
| jquery.js:8:18:8:34 | "XSS: " + tainted | Cross-site scripting vulnerability due to $@. | jquery.js:2:17:2:33 | document.location | user-provided value |
4+
| react-native.js:8:18:8:24 | tainted | Cross-site scripting vulnerability due to $@. | react-native.js:7:17:7:33 | req.param("code") | user-provided value |
5+
| react-native.js:9:27:9:33 | tainted | Cross-site scripting vulnerability due to $@. | react-native.js:7:17:7:33 | req.param("code") | user-provided value |
46
| string-manipulations.js:3:16:3:32 | document.location | Cross-site scripting vulnerability due to $@. | string-manipulations.js:3:16:3:32 | document.location | user-provided value |
57
| string-manipulations.js:4:16:4:37 | documen ... on.href | Cross-site scripting vulnerability due to $@. | string-manipulations.js:4:16:4:32 | document.location | user-provided value |
68
| string-manipulations.js:5:16:5:47 | documen ... lueOf() | Cross-site scripting vulnerability due to $@. | string-manipulations.js:5:16:5:32 | document.location | user-provided value |
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import express from 'express';
2+
import { WebView } from 'react-native';
3+
4+
var app = express();
5+
6+
app.get('/some/path', function(req, res) {
7+
let tainted = req.param("code");
8+
<WebView html={tainted}/>; // NOT OK
9+
<WebView source={{html: tainted}}/>; // NOT OK
10+
});

javascript/ql/test/query-tests/Security/CWE-094/CodeInjection.expected

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
| express.js:7:24:7:69 | "return ... + "];" | $@ flows to here and is interpreted as code. | express.js:7:44:7:62 | req.param("wobble") | User-provided value |
1616
| express.js:9:34:9:79 | "return ... + "];" | $@ flows to here and is interpreted as code. | express.js:9:54:9:72 | req.param("wobble") | User-provided value |
1717
| express.js:12:8:12:53 | "return ... + "];" | $@ flows to here and is interpreted as code. | express.js:12:28:12:46 | req.param("wobble") | User-provided value |
18+
| react-native.js:8:32:8:38 | tainted | $@ flows to here and is interpreted as code. | react-native.js:7:17:7:33 | req.param("code") | User-provided value |
19+
| react-native.js:10:23:10:29 | tainted | $@ flows to here and is interpreted as code. | react-native.js:7:17:7:33 | req.param("code") | User-provided value |
1820
| tst.js:2:6:2:83 | documen ... t=")+8) | $@ flows to here and is interpreted as code. | tst.js:2:6:2:22 | document.location | User-provided value |
1921
| tst.js:5:12:5:33 | documen ... on.hash | $@ flows to here and is interpreted as code. | tst.js:5:12:5:28 | document.location | User-provided value |
2022
| tst.js:14:10:14:65 | documen ... , "$1") | $@ flows to here and is interpreted as code. | tst.js:14:10:14:24 | document.cookie | User-provided value |
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import express from 'express';
2+
import { WebView } from 'react-native';
3+
4+
var app = express();
5+
6+
app.get('/some/path', function(req, res) {
7+
let tainted = req.param("code");
8+
<WebView injectedJavaScript={tainted}/>; // NOT OK
9+
let wv = <WebView/>;
10+
wv.injectJavaScript(tainted); // NOT OK
11+
});

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,5 @@
99
| node.js:7:34:7:39 | target | Untrusted URL redirection due to $@. | node.js:6:26:6:32 | req.url | user-provided value |
1010
| node.js:15:34:15:45 | '/' + target | Untrusted URL redirection due to $@. | node.js:11:26:11:32 | req.url | user-provided value |
1111
| node.js:32:34:32:55 | target ... =" + me | Untrusted URL redirection due to $@. | node.js:29:26:29:32 | req.url | user-provided value |
12+
| react-native.js:8:17:8:23 | tainted | Untrusted URL redirection due to $@. | react-native.js:7:17:7:33 | req.param("code") | user-provided value |
13+
| react-native.js:9:26:9:32 | tainted | Untrusted URL redirection due to $@. | react-native.js:7:17:7:33 | req.param("code") | user-provided value |
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import express from 'express';
2+
import { WebView } from 'react-native';
3+
4+
var app = express();
5+
6+
app.get('/some/path', function(req, res) {
7+
let tainted = req.param("code");
8+
<WebView url={tainted}/>; // NOT OK
9+
<WebView source={{uri: tainted}}/>; // NOT OK
10+
});

0 commit comments

Comments
 (0)