Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
lgtm,codescanning
* A new query, `js/html-constructed-from-input`, has been added to the query suite,
highlighting libraries that may leave clients vulnerable to cross-site-scripting attacks.
77 changes: 77 additions & 0 deletions javascript/ql/src/Security/CWE-079/UnsafeHtmlConstruction.qhelp
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
When a library function dynamically constructs HTML in a potentially unsafe
way, then it's important to document to clients of the library that the function
should only be used with trusted inputs.

If the function is not documented as being potentially unsafe, then a client
may inadvertently use inputs containing unsafe HTML fragments, and thereby leave
the client vulnerable to cross-site scripting attacks.
</p>
</overview>
<recommendation>

<p>
Document all library functions that can lead to cross-site scripting
attacks, and guard against unsafe inputs where dynamic HTML
construction is not intended.
</p>
</recommendation>
<example>

<p>
The following example has a library function that renders a boldface name
by writing to the <code>innerHTML</code> property of an element.
</p>

<sample src="examples/unsafe-html-construction.js" />

<p>
This library function, however, does not escape unsafe HTML, and a client
that calls the function with user-supplied input may be vulnerable to
cross-site scripting attacks.
</p>

<p>
The library could either document that this function should not be used
with unsafe inputs, or use safe APIs such as <code>innerText</code>.
</p>

<sample src="examples/unsafe-html-construction_safe.js" />

<p>
Alternatively, a HTML sanitizer can be used to remove unsafe content.
</p>

<sample src="examples/unsafe-html-construction_sanitizer.js" />

</example>
<references>
<li>
OWASP:
<a href="https://www.owasp.org/index.php/DOM_based_XSS_Prevention_Cheat_Sheet">DOM based
XSS Prevention Cheat Sheet</a>.
</li>
<li>
OWASP:
<a href="https://www.owasp.org/index.php/XSS_%28Cross_Site_Scripting%29_Prevention_Cheat_Sheet">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>
</references>
</qhelp>
22 changes: 22 additions & 0 deletions javascript/ql/src/Security/CWE-079/UnsafeHtmlConstruction.ql
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* @name Unsafe HTML constructed from library input
* @description Using externally controlled strings to construct HTML might allow a malicious
* user to perform a cross-site scripting attack.
* @kind path-problem
* @problem.severity error
* @precision high
* @id js/html-constructed-from-input
* @tags security
* external/cwe/cwe-079
* external/cwe/cwe-116
*/

import javascript
import DataFlow::PathGraph
import semmle.javascript.security.dataflow.UnsafeHtmlConstruction::UnsafeHtmlConstruction

from DataFlow::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, Sink sinkNode
where cfg.hasFlowPath(source, sink) and sink.getNode() = sinkNode
select sinkNode, source, sink, "$@ based on $@ might later cause $@.", sinkNode,
sinkNode.describe(), source.getNode(), "library input", sinkNode.getSink(),
sinkNode.getVulnerabilityKind().toLowerCase()
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = function showBoldName(name) {
document.getElementById('name').innerHTML = "<b>" + name + "</b>";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = function showBoldName(name) {
const bold = document.createElement('b');
bold.innerText = name;
document.getElementById('name').appendChild(bold);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@

const striptags = require('striptags');
module.exports = function showBoldName(name) {
document.getElementById('name').innerHTML = "<b>" + striptags(name) + "</b>";
}
11 changes: 11 additions & 0 deletions javascript/ql/src/semmle/javascript/dataflow/Configuration.qll
Original file line number Diff line number Diff line change
Expand Up @@ -2068,3 +2068,14 @@ class VarAccessBarrier extends DataFlow::Node {
)
}
}

/**
* Holds if there is a path without unmatched return steps from `source` to `sink`.
*/
predicate hasPathWithoutUnmatchedReturn(SourcePathNode source, SinkPathNode sink) {
exists(MidPathNode mid |
source.getASuccessor*() = mid and
sink = mid.getASuccessor() and
mid.getPathSummary().hasReturn() = false
)
}
Loading