Skip to content

Commit 65d93c9

Browse files
committed
detect for DOM elements from DOM events in React
1 parent 458dda9 commit 65d93c9

File tree

3 files changed

+29
-0
lines changed

3 files changed

+29
-0
lines changed

javascript/ql/src/semmle/javascript/DOM.qll

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,15 @@ module DOM {
357357
}
358358
}
359359

360+
/**
361+
* Gets a reference to a DOM event.
362+
*/
363+
private DataFlow::SourceNode domEventSource() {
364+
exists(JSXAttribute attr | attr.getName().matches("on%") |
365+
result = attr.getValue().flow().getABoundFunctionValue(0).getParameter(0)
366+
)
367+
}
368+
360369
/** Gets a data flow node that refers directly to a value from the DOM. */
361370
DataFlow::SourceNode domValueSource() { result instanceof DomValueSource::Range }
362371

@@ -368,6 +377,10 @@ module DOM {
368377
t.start() and
369378
result = domValueRef().getAMethodCall(["item", "namedItem"])
370379
or
380+
// e.g. <form onSubmit={e => e.target}/>
381+
t.startInProp("target") and
382+
result = domEventSource()
383+
or
371384
exists(DataFlow::TypeTracker t2 | result = domValueRef(t2).track(t2, t))
372385
}
373386

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ nodes
3030
| forms.js:45:21:45:26 | values |
3131
| forms.js:45:21:45:33 | values.stooge |
3232
| forms.js:45:21:45:33 | values.stooge |
33+
| forms.js:57:19:57:32 | e.target.value |
34+
| forms.js:57:19:57:32 | e.target.value |
35+
| forms.js:57:19:57:32 | e.target.value |
3336
| xss-through-dom.js:2:16:2:34 | $("textarea").val() |
3437
| xss-through-dom.js:2:16:2:34 | $("textarea").val() |
3538
| xss-through-dom.js:2:16:2:34 | $("textarea").val() |
@@ -106,6 +109,7 @@ edges
106109
| forms.js:44:21:44:26 | values | forms.js:45:21:45:26 | values |
107110
| forms.js:45:21:45:26 | values | forms.js:45:21:45:33 | values.stooge |
108111
| forms.js:45:21:45:26 | values | forms.js:45:21:45:33 | values.stooge |
112+
| forms.js:57:19:57:32 | e.target.value | forms.js:57:19:57:32 | e.target.value |
109113
| xss-through-dom.js:2:16:2:34 | $("textarea").val() | xss-through-dom.js:2:16:2:34 | $("textarea").val() |
110114
| xss-through-dom.js:4:16:4:40 | $(".som ... .text() | xss-through-dom.js:4:16:4:40 | $(".som ... .text() |
111115
| xss-through-dom.js:8:16:8:53 | $(".som ... arget") | xss-through-dom.js:8:16:8:53 | $(".som ... arget") |
@@ -132,6 +136,7 @@ edges
132136
| forms.js:29:23:29:34 | values.email | forms.js:28:20:28:25 | values | forms.js:29:23:29:34 | values.email | $@ is reinterpreted as HTML without escaping meta-characters. | forms.js:28:20:28:25 | values | DOM text |
133137
| forms.js:35:19:35:30 | values.email | forms.js:34:13:34:18 | values | forms.js:35:19:35:30 | values.email | $@ is reinterpreted as HTML without escaping meta-characters. | forms.js:34:13:34:18 | values | DOM text |
134138
| forms.js:45:21:45:33 | values.stooge | forms.js:44:21:44:26 | values | forms.js:45:21:45:33 | values.stooge | $@ is reinterpreted as HTML without escaping meta-characters. | forms.js:44:21:44:26 | values | DOM text |
139+
| forms.js:57:19:57:32 | e.target.value | forms.js:57:19:57:32 | e.target.value | forms.js:57:19:57:32 | e.target.value | $@ is reinterpreted as HTML without escaping meta-characters. | forms.js:57:19:57:32 | e.target.value | DOM text |
135140
| xss-through-dom.js:2:16:2:34 | $("textarea").val() | xss-through-dom.js:2:16:2:34 | $("textarea").val() | xss-through-dom.js:2:16:2:34 | $("textarea").val() | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:2:16:2:34 | $("textarea").val() | DOM text |
136141
| xss-through-dom.js:4:16:4:40 | $(".som ... .text() | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:4:16:4:40 | $(".som ... .text() | DOM text |
137142
| xss-through-dom.js:8:16:8:53 | $(".som ... arget") | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | $@ is reinterpreted as HTML without escaping meta-characters. | xss-through-dom.js:8:16:8:53 | $(".som ... arget") | DOM text |

javascript/ql/test/query-tests/Security/CWE-079/XssThroughDom/forms.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,15 @@ const App = () => (
5151
</form>
5252
)}
5353
/>
54+
);
55+
56+
function plainSubmit(e) {
57+
$("#id").html(e.target.value); // NOT OK
58+
}
59+
60+
const plainReact = () => (
61+
<form onSubmit={e => plainSubmit(e)}>
62+
<input type="text" value={this.state.value} onChange={this.handleChange} />
63+
<input type="submit" value="Submit" />
64+
</form>
5465
)

0 commit comments

Comments
 (0)