Skip to content

Commit cf9ab83

Browse files
authored
Merge pull request github#6498 from bananabr/main
Approved by asgerf
2 parents c3e122f + b8ce5a6 commit cf9ab83

File tree

3 files changed

+153
-0
lines changed

3 files changed

+153
-0
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
6+
<overview>
7+
<p>
8+
Directly pasting user input from the clipboard to a webpage
9+
without properly sanitizing the input first, allows for a cross-site scripting vulnerability.
10+
</p>
11+
</overview>
12+
13+
<recommendation>
14+
<p>
15+
To guard against cross-site scripting, consider using contextual output encoding/escaping before
16+
writing user input to the page, or one of the other solutions that are mentioned in the
17+
references.
18+
</p>
19+
</recommendation>
20+
21+
<example>
22+
<p>
23+
The following example shows a div element whose HTML content comes directly from the clipboard being written to the DOM,
24+
leaving the website vulnerable to cross-site scripting.
25+
</p>
26+
<sample src="examples/clipboard-xss-sample.js" />
27+
</example>
28+
29+
<references>
30+
<li>
31+
OWASP:
32+
<a href="https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html">DOM based
33+
XSS Prevention Cheat Sheet</a>.
34+
</li>
35+
<li>
36+
OWASP:
37+
<a href="https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html">XSS
38+
(Cross Site Scripting) Prevention Cheat Sheet</a>.
39+
</li>
40+
<li>
41+
OWASP
42+
<a href="https://www.owasp.org/index.php/DOM_Based_XSS">DOM Based XSS</a>.
43+
</li>
44+
<li>
45+
OWASP
46+
<a href="https://www.owasp.org/index.php/Types_of_Cross-Site_Scripting">Types of Cross-Site
47+
Scripting</a>.
48+
</li>
49+
<li>
50+
Wikipedia: <a href="http://en.wikipedia.org/wiki/Cross-site_scripting">Cross-site scripting</a>.
51+
</li>
52+
<li>
53+
Securitum:
54+
<a href="https://research.securitum.com/the-curious-case-of-copy-paste/">Clipboard security research</a>.
55+
</li>
56+
</references>
57+
</qhelp>
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/**
2+
* @name Client-side clipboard-based cross-site scripting
3+
* @description Pasting clipboard input directly to the DOM without proper sanitization allows for
4+
* a cross-site scripting vulnerability.
5+
* @kind path-problem
6+
* @problem.severity error
7+
* @security-severity 3.1
8+
* @precision high
9+
* @id js/clipboard-xss
10+
* @tags security
11+
* external/cwe/cwe-079
12+
*/
13+
14+
import javascript
15+
import DataFlow
16+
import semmle.javascript.security.dataflow.DomBasedXssQuery as DomBasedXss
17+
import DataFlow::PathGraph
18+
19+
/*
20+
* Gets references to clipboardData DataTransfer objects
21+
* https://developer.mozilla.org/en-US/docs/Web/API/ClipboardEvent/clipboardData
22+
*/
23+
24+
SourceNode clipboardDataTransferSource(TypeTracker t) {
25+
t.start() and
26+
exists(DataFlow::PropRead pr | pr.getPropertyName() = "clipboardData" and result = pr)
27+
or
28+
exists(TypeTracker t2 | result = clipboardDataTransferSource(t2).track(t2, t))
29+
}
30+
31+
SourceNode clipboardDataTransferSource() {
32+
result = clipboardDataTransferSource(TypeTracker::end())
33+
}
34+
35+
/*
36+
* Gets references to the result of a call to getData on a DataTransfer object
37+
* https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/getData
38+
*/
39+
40+
SourceNode clipboardDataSource(TypeTracker t) {
41+
t.start() and
42+
result = clipboardDataTransferSource().getAMethodCall("getData")
43+
or
44+
exists(TypeTracker t2 | result = clipboardDataSource(t2).track(t2, t))
45+
}
46+
47+
SourceNode clipboardDataSource() { result = clipboardDataSource(TypeTracker::end()) }
48+
49+
class ClipboardSource extends DataFlow::Node {
50+
ClipboardSource() { this = clipboardDataSource() }
51+
}
52+
53+
class ClipboardHtmlInjectionConfiguration extends DomBasedXss::HtmlInjectionConfiguration {
54+
override predicate isSource(DataFlow::Node source) { source instanceof ClipboardSource }
55+
}
56+
57+
class ClipboardJQueryHtmlOrSelectorInjectionConfiguration extends DomBasedXss::JQueryHtmlOrSelectorInjectionConfiguration {
58+
override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) {
59+
// Reuse any source not derived from location
60+
source instanceof ClipboardSource and
61+
(
62+
label.isTaint()
63+
or
64+
label.isData() // Require transformation before reaching sink
65+
)
66+
}
67+
}
68+
69+
from DataFlow::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
70+
where
71+
(
72+
cfg instanceof ClipboardHtmlInjectionConfiguration or
73+
cfg instanceof ClipboardJQueryHtmlOrSelectorInjectionConfiguration
74+
) and
75+
cfg.hasFlowPath(source, sink)
76+
select sink.getNode(), source, sink,
77+
sink.getNode().(DomBasedXss::Sink).getVulnerabilityKind() + " vulnerability due to $@.",
78+
source.getNode(), "user-provided clipboard value"
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
function paste(e) {
2+
const { clipboardData } = e.originalEvent;
3+
if (!clipboardData) return;
4+
5+
const text = clipboardData.getData('text/plain');
6+
const html = clipboardData.getData('text/html');
7+
if (!text && !html) return;
8+
9+
e.preventDefault();
10+
11+
const div = document.createElement('div');
12+
if (html) {
13+
div.innerHTML = html;
14+
} else {
15+
div.textContent = text;
16+
}
17+
document.body.append(div);
18+
}

0 commit comments

Comments
 (0)