mirror of
https://github.com/github/codeql.git
synced 2026-05-01 03:35:13 +02:00
JS: query to find dynamic creations of DOM elements that use untrusted sources
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* @name Dynamic creation of untrusted source use
|
||||
* @description Finds dynamically created DOM elements that may use
|
||||
* behaviour from http-URLs without integrity checks.
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @tags security
|
||||
* @id js/dynamic-creation-of-untrusted-source-use
|
||||
*/
|
||||
|
||||
import javascript
|
||||
import DataFlow::PathGraph
|
||||
|
||||
predicate isCreateElementNode(DataFlow::CallNode call, string name) {
|
||||
call = DataFlow::globalVarRef("document").getAMethodCall("createElement") and
|
||||
call.getArgument(0).getStringValue().toLowerCase() = name
|
||||
}
|
||||
|
||||
predicate isCreateScriptNodeWoIntegrityCheck(DataFlow::CallNode call) {
|
||||
isCreateElementNode(call, "script") and
|
||||
not exists(DataFlow::Node rhs | isScriptPropWrite(call, "integrity", rhs))
|
||||
}
|
||||
|
||||
predicate isScriptPropWrite(
|
||||
DataFlow::CallNode createElementCall, string propName, DataFlow::Node rhs
|
||||
) {
|
||||
exists(DataFlow::PropWrite assignment |
|
||||
isCreateElementNode(createElementCall, "script") and
|
||||
assignment.writes(createElementCall.getALocalUse(), propName, rhs)
|
||||
)
|
||||
}
|
||||
|
||||
class DynamicCreationOfUntrustedSourceUseCfg extends TaintTracking::Configuration {
|
||||
DynamicCreationOfUntrustedSourceUseCfg() { this = "DynamicCreationOfUntrustedSourceUseCfg" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
exists(StringLiteral s | source = s.flow() |
|
||||
s.getValue() = ["http:", "//"] + any(string rest) // TODO match HTTP HtTp etc
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(DataFlow::CallNode createElementCall |
|
||||
isScriptPropWrite(createElementCall, "src", sink) and
|
||||
isCreateScriptNodeWoIntegrityCheck(createElementCall)
|
||||
or
|
||||
exists(DataFlow::CallNode iframeCreateCall, DataFlow::PropWrite srcWrite |
|
||||
isCreateElementNode(iframeCreateCall, "iframe") and
|
||||
srcWrite.getRhs() = sink and
|
||||
srcWrite.getBase() = iframeCreateCall.getALocalUse()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
from DynamicCreationOfUntrustedSourceUseCfg cfg, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where cfg.hasFlowPath(source, sink)
|
||||
select sink.getNode(), source, sink, "Illegal flow from $@.", source.getNode(), "here"
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: newQuery
|
||||
---
|
||||
* A new query, `js/dynamic-creation-of-untrusted-source-use`, has been added to the query suite. It finds code
|
||||
that creates HTML elements that load functionality from untrusted sources, like a `script`- or `iframe`-element using http-links.
|
||||
The query is run by default.
|
||||
@@ -0,0 +1,20 @@
|
||||
nodes
|
||||
| dynamic.html:8:27:8:97 | ('https ... //www') |
|
||||
| dynamic.html:8:27:8:118 | ('https ... /ga.js' |
|
||||
| dynamic.html:8:27:8:118 | ('https ... /ga.js' |
|
||||
| dynamic.html:8:28:8:96 | 'https: ... ://www' |
|
||||
| dynamic.html:8:85:8:96 | 'http://www' |
|
||||
| dynamic.html:8:85:8:96 | 'http://www' |
|
||||
| dynamic.html:18:26:18:50 | 'http:/ ... e.com/' |
|
||||
| dynamic.html:18:26:18:50 | 'http:/ ... e.com/' |
|
||||
| dynamic.html:18:26:18:50 | 'http:/ ... e.com/' |
|
||||
edges
|
||||
| dynamic.html:8:27:8:97 | ('https ... //www') | dynamic.html:8:27:8:118 | ('https ... /ga.js' |
|
||||
| dynamic.html:8:27:8:97 | ('https ... //www') | dynamic.html:8:27:8:118 | ('https ... /ga.js' |
|
||||
| dynamic.html:8:28:8:96 | 'https: ... ://www' | dynamic.html:8:27:8:97 | ('https ... //www') |
|
||||
| dynamic.html:8:85:8:96 | 'http://www' | dynamic.html:8:28:8:96 | 'https: ... ://www' |
|
||||
| dynamic.html:8:85:8:96 | 'http://www' | dynamic.html:8:28:8:96 | 'https: ... ://www' |
|
||||
| dynamic.html:18:26:18:50 | 'http:/ ... e.com/' | dynamic.html:18:26:18:50 | 'http:/ ... e.com/' |
|
||||
#select
|
||||
| dynamic.html:8:27:8:118 | ('https ... /ga.js' | dynamic.html:8:85:8:96 | 'http://www' | dynamic.html:8:27:8:118 | ('https ... /ga.js' | Illegal flow from $@. | dynamic.html:8:85:8:96 | 'http://www' | here |
|
||||
| dynamic.html:18:26:18:50 | 'http:/ ... e.com/' | dynamic.html:18:26:18:50 | 'http:/ ... e.com/' | dynamic.html:18:26:18:50 | 'http:/ ... e.com/' | Illegal flow from $@. | dynamic.html:18:26:18:50 | 'http:/ ... e.com/' | here |
|
||||
@@ -0,0 +1 @@
|
||||
Security/CWE-830/DynamicCreationOfUntrustedSourceUse.ql
|
||||
29
javascript/ql/test/query-tests/Security/CWE-830/dynamic.html
Normal file
29
javascript/ql/test/query-tests/Security/CWE-830/dynamic.html
Normal file
@@ -0,0 +1,29 @@
|
||||
<html>
|
||||
<head>
|
||||
<script type="text/javascript">
|
||||
(function() {
|
||||
// NOT OK (no integrity attribute)
|
||||
var scrpt = document.createElement('script');
|
||||
scrpt.type = 'text/javascript';
|
||||
scrpt.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.cdn.local/ga.js';
|
||||
|
||||
// OK (integrity digest present)
|
||||
var scrpt2 = document.createElement('script');
|
||||
scrpt2.type = 'text/javascript';
|
||||
scrpt2.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.cdn.local/ga.js';
|
||||
scrpt2.integrity = 'sha256-h0UuK3mE9taiYlB5u9vT9A0s/XDgkfVd+F4VhN/sky=';
|
||||
|
||||
// NOT OK (http URL)
|
||||
var ifrm = document.createElement('iframe');
|
||||
ifrm.src = 'http://www.example.com/';
|
||||
|
||||
// OK (https URL)
|
||||
var ifrm2 = document.createElement('iframe');
|
||||
ifrm2.src = 'https://www.example.com/';
|
||||
})();
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
hello
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user