Skip to content

Commit 7f592a6

Browse files
committed
merge Clipboard.qll and DragAndDrop.qll, and support InputEvent
1 parent 34abef8 commit 7f592a6

File tree

7 files changed

+143
-153
lines changed

7 files changed

+143
-153
lines changed

javascript/ql/lib/javascript.qll

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ import semmle.javascript.frameworks.ComposedFunctions
7979
import semmle.javascript.frameworks.Classnames
8080
import semmle.javascript.frameworks.ClassValidator
8181
import semmle.javascript.frameworks.ClientRequests
82-
import semmle.javascript.frameworks.Clipboard
8382
import semmle.javascript.frameworks.ClosureLibrary
8483
import semmle.javascript.frameworks.CookieLibraries
8584
import semmle.javascript.frameworks.Credentials
@@ -88,7 +87,7 @@ import semmle.javascript.frameworks.D3
8887
import semmle.javascript.frameworks.data.ModelsAsData
8988
import semmle.javascript.frameworks.DateFunctions
9089
import semmle.javascript.frameworks.DigitalOcean
91-
import semmle.javascript.frameworks.DragAndDrop
90+
import semmle.javascript.frameworks.DomEvents
9291
import semmle.javascript.frameworks.Electron
9392
import semmle.javascript.frameworks.EventEmitter
9493
import semmle.javascript.frameworks.Files

javascript/ql/lib/semmle/javascript/frameworks/Clipboard.qll

Lines changed: 0 additions & 75 deletions
This file was deleted.
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/**
2+
* Provides predicates for reasoning about events from the DOM that introduce tainted data.
3+
*/
4+
5+
import javascript
6+
7+
/** Gets the name of a DOM event that might introduce tainted data. */
8+
private string getATaintedDomEvent() { result = ["paste", "drop", "beforeinput"] }
9+
10+
/**
11+
* Gets a jQuery event that might introduce tainted data.
12+
* E.g. `e` in `$("#foo").on("paste", function(e) { ... })`.
13+
*/
14+
private DataFlow::SourceNode taintedJQueryEvent(DataFlow::TypeTracker t, string event) {
15+
t.start() and
16+
exists(DataFlow::CallNode call |
17+
call = JQuery::objectRef().getAMethodCall(["bind", "on", "live", "one", "delegate"]) and
18+
call.getArgument(0).mayHaveStringValue(event) and
19+
event = getATaintedDomEvent()
20+
|
21+
result = call.getCallback(call.getNumArgument() - 1).getParameter(0)
22+
)
23+
or
24+
exists(DataFlow::TypeTracker t2 | result = taintedJQueryEvent(t2, event).track(t2, t))
25+
}
26+
27+
/**
28+
* Gets a DOM event that might introduce tainted data.
29+
* E.g. `e` in `document.addEventListener("paste", e => { ... })`.
30+
*/
31+
private DataFlow::SourceNode taintedEvent(DataFlow::TypeTracker t, string event) {
32+
t.start() and
33+
exists(DataFlow::CallNode call | call = DOM::domValueRef().getAMemberCall("addEventListener") |
34+
call.getArgument(0).mayHaveStringValue(event) and
35+
event = getATaintedDomEvent() and
36+
result = call.getCallback(1).getParameter(0)
37+
)
38+
or
39+
t.start() and
40+
exists(DataFlow::ParameterNode pn |
41+
// https://developer.mozilla.org/en-US/docs/Web/API/ClipboardEvent
42+
pn.hasUnderlyingType("ClipboardEvent") and
43+
result = pn and
44+
event = "paste"
45+
or
46+
// https://developer.mozilla.org/en-US/docs/Web/API/DragEvent
47+
pn.hasUnderlyingType("DragEvent") and
48+
result = pn and
49+
event = "drop"
50+
or
51+
// https://developer.mozilla.org/en-US/docs/Web/API/InputEvent
52+
pn.hasUnderlyingType("InputEvent") and
53+
result = pn and
54+
event = "beforeinput"
55+
)
56+
or
57+
t.start() and
58+
exists(DataFlow::PropWrite pw | pw = DOM::domValueRef().getAPropertyWrite() |
59+
pw.getPropertyName() = "on" + event and
60+
event = ["paste", "drop"] and // doesn't work for beforeinput, it's just not part of the API
61+
result = pw.getRhs().getABoundFunctionValue(0).getParameter(0)
62+
)
63+
or
64+
t.start() and
65+
result = taintedJQueryEvent(DataFlow::TypeTracker::end(), event).getAPropertyRead("originalEvent")
66+
or
67+
exists(DataFlow::TypeTracker t2 | result = taintedEvent(t2, event).track(t2, t))
68+
}
69+
70+
/**
71+
* Gets a reference to a DataTransfer object.
72+
* https://developer.mozilla.org/en-US/docs/Web/API/ClipboardEvent/clipboardData
73+
*/
74+
private DataFlow::SourceNode taintedDataTransfer(DataFlow::TypeTracker t) {
75+
t.start() and
76+
result = taintedEvent(DataFlow::TypeTracker::end(), "paste").getAPropertyRead("clipboardData")
77+
or
78+
t.start() and
79+
result =
80+
taintedEvent(DataFlow::TypeTracker::end(), ["drop", "beforeinput"])
81+
.getAPropertyRead("dataTransfer")
82+
or
83+
exists(DataFlow::TypeTracker t2 | result = taintedDataTransfer(t2).track(t2, t))
84+
}
85+
86+
/**
87+
* A reference to data from a DataTransfer object, which might originate from e.g. the clipboard.
88+
* Seen as a source for DOM-based XSS.
89+
*/
90+
private class TaintedDataTransfer extends RemoteFlowSource {
91+
TaintedDataTransfer() {
92+
this = taintedDataTransfer(DataFlow::TypeTracker::end()).getAMethodCall("getData")
93+
}
94+
95+
override string getSourceType() { result = "Clipboard data" }
96+
}

javascript/ql/lib/semmle/javascript/frameworks/DragAndDrop.qll

Lines changed: 0 additions & 75 deletions
This file was deleted.

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,14 @@ nodes
152152
| clipboard.ts:73:29:73:39 | droppedHtml |
153153
| clipboard.ts:73:29:73:39 | droppedHtml |
154154
| clipboard.ts:73:29:73:39 | droppedHtml |
155+
| clipboard.ts:98:15:98:54 | html |
156+
| clipboard.ts:98:15:98:54 | html |
157+
| clipboard.ts:98:22:98:54 | dataTra ... /html') |
158+
| clipboard.ts:98:22:98:54 | dataTra ... /html') |
159+
| clipboard.ts:98:22:98:54 | dataTra ... /html') |
160+
| clipboard.ts:99:23:99:26 | html |
161+
| clipboard.ts:99:23:99:26 | html |
162+
| clipboard.ts:99:23:99:26 | html |
155163
| custom-element.js:5:26:5:36 | window.name |
156164
| custom-element.js:5:26:5:36 | window.name |
157165
| custom-element.js:5:26:5:36 | window.name |
@@ -1202,6 +1210,14 @@ edges
12021210
| clipboard.ts:71:27:71:62 | e.clipb ... /html') | clipboard.ts:71:13:71:62 | droppedHtml |
12031211
| clipboard.ts:71:27:71:62 | e.clipb ... /html') | clipboard.ts:71:13:71:62 | droppedHtml |
12041212
| clipboard.ts:71:27:71:62 | e.clipb ... /html') | clipboard.ts:71:13:71:62 | droppedHtml |
1213+
| clipboard.ts:98:15:98:54 | html | clipboard.ts:99:23:99:26 | html |
1214+
| clipboard.ts:98:15:98:54 | html | clipboard.ts:99:23:99:26 | html |
1215+
| clipboard.ts:98:15:98:54 | html | clipboard.ts:99:23:99:26 | html |
1216+
| clipboard.ts:98:15:98:54 | html | clipboard.ts:99:23:99:26 | html |
1217+
| clipboard.ts:98:22:98:54 | dataTra ... /html') | clipboard.ts:98:15:98:54 | html |
1218+
| clipboard.ts:98:22:98:54 | dataTra ... /html') | clipboard.ts:98:15:98:54 | html |
1219+
| clipboard.ts:98:22:98:54 | dataTra ... /html') | clipboard.ts:98:15:98:54 | html |
1220+
| clipboard.ts:98:22:98:54 | dataTra ... /html') | clipboard.ts:98:15:98:54 | html |
12051221
| custom-element.js:5:26:5:36 | window.name | custom-element.js:5:26:5:36 | window.name |
12061222
| d3.js:4:12:4:22 | window.name | d3.js:11:15:11:24 | getTaint() |
12071223
| d3.js:4:12:4:22 | window.name | d3.js:11:15:11:24 | getTaint() |
@@ -2164,6 +2180,7 @@ edges
21642180
| clipboard.ts:33:19:33:68 | e.origi ... /html') | clipboard.ts:33:19:33:68 | e.origi ... /html') | clipboard.ts:33:19:33:68 | e.origi ... /html') | Cross-site scripting vulnerability due to $@. | clipboard.ts:33:19:33:68 | e.origi ... /html') | user-provided value |
21652181
| clipboard.ts:50:29:50:32 | html | clipboard.ts:43:22:43:55 | clipboa ... /html') | clipboard.ts:50:29:50:32 | html | Cross-site scripting vulnerability due to $@. | clipboard.ts:43:22:43:55 | clipboa ... /html') | user-provided value |
21662182
| clipboard.ts:73:29:73:39 | droppedHtml | clipboard.ts:71:27:71:62 | e.clipb ... /html') | clipboard.ts:73:29:73:39 | droppedHtml | Cross-site scripting vulnerability due to $@. | clipboard.ts:71:27:71:62 | e.clipb ... /html') | user-provided value |
2183+
| clipboard.ts:99:23:99:26 | html | clipboard.ts:98:22:98:54 | dataTra ... /html') | clipboard.ts:99:23:99:26 | html | Cross-site scripting vulnerability due to $@. | clipboard.ts:98:22:98:54 | dataTra ... /html') | user-provided value |
21672184
| custom-element.js:5:26:5:36 | window.name | custom-element.js:5:26:5:36 | window.name | custom-element.js:5:26:5:36 | window.name | Cross-site scripting vulnerability due to $@. | custom-element.js:5:26:5:36 | window.name | user-provided value |
21682185
| d3.js:11:15:11:24 | getTaint() | d3.js:4:12:4:22 | window.name | d3.js:11:15:11:24 | getTaint() | Cross-site scripting vulnerability due to $@. | d3.js:4:12:4:22 | window.name | user-provided value |
21692186
| d3.js:12:20:12:29 | getTaint() | d3.js:4:12:4:22 | window.name | d3.js:12:20:12:29 | getTaint() | Cross-site scripting vulnerability due to $@. | d3.js:4:12:4:22 | window.name | user-provided value |

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,14 @@ nodes
152152
| clipboard.ts:73:29:73:39 | droppedHtml |
153153
| clipboard.ts:73:29:73:39 | droppedHtml |
154154
| clipboard.ts:73:29:73:39 | droppedHtml |
155+
| clipboard.ts:98:15:98:54 | html |
156+
| clipboard.ts:98:15:98:54 | html |
157+
| clipboard.ts:98:22:98:54 | dataTra ... /html') |
158+
| clipboard.ts:98:22:98:54 | dataTra ... /html') |
159+
| clipboard.ts:98:22:98:54 | dataTra ... /html') |
160+
| clipboard.ts:99:23:99:26 | html |
161+
| clipboard.ts:99:23:99:26 | html |
162+
| clipboard.ts:99:23:99:26 | html |
155163
| custom-element.js:5:26:5:36 | window.name |
156164
| custom-element.js:5:26:5:36 | window.name |
157165
| custom-element.js:5:26:5:36 | window.name |
@@ -1252,6 +1260,14 @@ edges
12521260
| clipboard.ts:71:27:71:62 | e.clipb ... /html') | clipboard.ts:71:13:71:62 | droppedHtml |
12531261
| clipboard.ts:71:27:71:62 | e.clipb ... /html') | clipboard.ts:71:13:71:62 | droppedHtml |
12541262
| clipboard.ts:71:27:71:62 | e.clipb ... /html') | clipboard.ts:71:13:71:62 | droppedHtml |
1263+
| clipboard.ts:98:15:98:54 | html | clipboard.ts:99:23:99:26 | html |
1264+
| clipboard.ts:98:15:98:54 | html | clipboard.ts:99:23:99:26 | html |
1265+
| clipboard.ts:98:15:98:54 | html | clipboard.ts:99:23:99:26 | html |
1266+
| clipboard.ts:98:15:98:54 | html | clipboard.ts:99:23:99:26 | html |
1267+
| clipboard.ts:98:22:98:54 | dataTra ... /html') | clipboard.ts:98:15:98:54 | html |
1268+
| clipboard.ts:98:22:98:54 | dataTra ... /html') | clipboard.ts:98:15:98:54 | html |
1269+
| clipboard.ts:98:22:98:54 | dataTra ... /html') | clipboard.ts:98:15:98:54 | html |
1270+
| clipboard.ts:98:22:98:54 | dataTra ... /html') | clipboard.ts:98:15:98:54 | html |
12551271
| custom-element.js:5:26:5:36 | window.name | custom-element.js:5:26:5:36 | window.name |
12561272
| d3.js:4:12:4:22 | window.name | d3.js:11:15:11:24 | getTaint() |
12571273
| d3.js:4:12:4:22 | window.name | d3.js:11:15:11:24 | getTaint() |

javascript/ql/test/query-tests/Security/CWE-079/DomBasedXss/clipboard.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,4 +86,16 @@ async function getClipboardData(e: ClipboardEvent): Promise<Array<File | string>
8686

8787
const imageItems = Array.from(dropItems);
8888
return imageItems;
89-
}
89+
}
90+
91+
// inputevent
92+
(function () {
93+
let div = document.createElement("div");
94+
div.addEventListener("beforeinput", function (e: InputEvent) {
95+
const { data, inputType, isComposing, dataTransfer } = e;
96+
if (!dataTransfer) return;
97+
98+
const html = dataTransfer.getData('text/html');
99+
$("#id").html(html); // NOT OK
100+
});
101+
})();

0 commit comments

Comments
 (0)