mirror of
https://github.com/github/codeql.git
synced 2026-04-29 02:35:15 +02:00
new Experimental query ClipboardBasedXss
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>
|
||||
Directly pasting user input from the clipboard to a webpage
|
||||
without properly sanitizing the input first, allows for a cross-site scripting vulnerability.
|
||||
</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>
|
||||
To guard against cross-site scripting, consider using contextual output encoding/escaping before
|
||||
writing user input to the page, or one of the other solutions that are mentioned in the
|
||||
references.
|
||||
</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>
|
||||
The following example shows a div element whose HTML content comes directly from the clipboard being written to the DOM,
|
||||
leaving the website vulnerable to cross-site scripting.
|
||||
</p>
|
||||
<sample src="examples/clipboard-xss-sample.js" />
|
||||
</example>
|
||||
|
||||
<references>
|
||||
<li>
|
||||
OWASP:
|
||||
<a href="https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html">DOM based
|
||||
XSS Prevention Cheat Sheet</a>.
|
||||
</li>
|
||||
<li>
|
||||
OWASP:
|
||||
<a href="https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html">XSS
|
||||
(Cross Site Scripting) Prevention Cheat Sheet</a>.
|
||||
</li>
|
||||
<li>
|
||||
OWASP
|
||||
<a href="https://www.owasp.org/index.php/DOM_Based_XSS">DOM Based XSS</a>.
|
||||
</li>
|
||||
<li>
|
||||
OWASP
|
||||
<a href="https://www.owasp.org/index.php/Types_of_Cross-Site_Scripting">Types of Cross-Site
|
||||
Scripting</a>.
|
||||
</li>
|
||||
<li>
|
||||
Wikipedia: <a href="http://en.wikipedia.org/wiki/Cross-site_scripting">Cross-site scripting</a>.
|
||||
</li>
|
||||
<li>
|
||||
Securitum:
|
||||
<a href="https://research.securitum.com/the-curious-case-of-copy-paste/">Clipboard security research</a>.
|
||||
</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* @name Client-side clipboard-based cross-site scripting
|
||||
* @description Pasting clipboard input directly to the DOM without proper sanitization allows for
|
||||
* a cross-site scripting vulnerability.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @security-severity 3.1
|
||||
* @precision high
|
||||
* @id js/clipboard-xss
|
||||
* @tags security
|
||||
* external/cwe/cwe-079
|
||||
*/
|
||||
|
||||
import javascript
|
||||
import DataFlow
|
||||
import semmle.javascript.security.dataflow.DomBasedXss
|
||||
import DataFlow::PathGraph
|
||||
|
||||
/*
|
||||
* Gets references to clipboardData DataTransfer objects
|
||||
* https://developer.mozilla.org/en-US/docs/Web/API/ClipboardEvent/clipboardData
|
||||
*/
|
||||
|
||||
SourceNode clipboardDataTransferSource(TypeTracker t) {
|
||||
t.start() and
|
||||
exists(DataFlow::PropRead pr | pr.getPropertyName() = "clipboardData" and pr.flowsTo(result))
|
||||
or
|
||||
exists(TypeTracker t2 | result = clipboardDataSource(t2).track(t2, t))
|
||||
}
|
||||
|
||||
SourceNode clipboardDataTransferSource() {
|
||||
result = clipboardDataTransferSource(TypeTracker::end())
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets references to the result of a call to getData on a DataTransfer object
|
||||
* https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/getData
|
||||
*/
|
||||
|
||||
SourceNode clipboardDataSource(TypeTracker t) {
|
||||
t.start() and
|
||||
clipboardDataTransferSource().getAMethodCall("getData").flowsTo(result)
|
||||
or
|
||||
exists(TypeTracker t2 | result = clipboardDataSource(t2).track(t2, t))
|
||||
}
|
||||
|
||||
SourceNode clipboardDataSource() { result = clipboardDataSource(TypeTracker::end()) }
|
||||
|
||||
class ClipboardSource extends DataFlow::Node {
|
||||
ClipboardSource() { this = clipboardDataSource() }
|
||||
}
|
||||
|
||||
class ClipboardHtmlInjectionConfiguration extends DomBasedXss::HtmlInjectionConfiguration {
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof ClipboardSource }
|
||||
}
|
||||
|
||||
class ClipboardJQueryHtmlOrSelectorInjectionConfiguration extends DomBasedXss::JQueryHtmlOrSelectorInjectionConfiguration {
|
||||
override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) {
|
||||
// Reuse any source not derived from location
|
||||
source instanceof ClipboardSource and
|
||||
(
|
||||
label.isTaint()
|
||||
or
|
||||
label.isData() // Require transformation before reaching sink
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
from DataFlow::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where
|
||||
(
|
||||
cfg instanceof ClipboardHtmlInjectionConfiguration or
|
||||
cfg instanceof ClipboardJQueryHtmlOrSelectorInjectionConfiguration
|
||||
) and
|
||||
cfg.hasFlowPath(source, sink)
|
||||
select sink.getNode(), source, sink,
|
||||
sink.getNode().(DomBasedXss::Sink).getVulnerabilityKind() + " vulnerability due to $@.",
|
||||
source.getNode(), "user-provided clipboard value"
|
||||
@@ -0,0 +1,18 @@
|
||||
function paste(e) {
|
||||
const { clipboardData } = e.originalEvent;
|
||||
if (!clipboardData) return;
|
||||
|
||||
const text = clipboardData.getData('text/plain');
|
||||
const html = clipboardData.getData('text/html');
|
||||
if (!text && !html) return;
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
const div = document.createElement('div');
|
||||
if (html) {
|
||||
div.innerHTML = html;
|
||||
} else {
|
||||
div.textContent = text;
|
||||
}
|
||||
document.body.append(div);
|
||||
}
|
||||
Reference in New Issue
Block a user