-
Notifications
You must be signed in to change notification settings - Fork 1.7k
/
Copy pathIncompleteUrlSchemeCheck.ql
61 lines (56 loc) · 2.03 KB
/
IncompleteUrlSchemeCheck.ql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/**
* @name Incomplete URL scheme check
* @description Checking for the "javascript:" URL scheme without also checking for "vbscript:"
* and "data:" suggests a logic error or even a security vulnerability.
* @kind problem
* @problem.severity warning
* @security-severity 7.8
* @precision high
* @id go/incomplete-url-scheme-check
* @tags security
* correctness
* external/cwe/cwe-020
*/
import go
/** A URL scheme that can be used to represent executable code. */
class DangerousScheme extends string {
DangerousScheme() { this = "data" or this = "javascript" or this = "vbscript" }
}
/** Gets a data-flow node that checks an instance of `g` against the given `scheme`. */
DataFlow::Node schemeCheck(GVN g, DangerousScheme scheme) {
// check of the form `nd.Scheme == scheme`
exists(DefinedType url, DataFlow::FieldReadNode fr, DataFlow::Node s |
url.hasQualifiedName("net/url", "URL") and
fr.readsField(g.getANode(), url.getField("Scheme")) and
s.getStringValue() = scheme and
result.(DataFlow::EqualityTestNode).eq(_, fr, s)
)
or
// check of the form `strings.HasPrefix(nd, "scheme:")`
exists(StringOps::HasPrefix hasPrefix | result = hasPrefix |
hasPrefix.getBaseString() = g.getANode() and
hasPrefix.getSubstring().getStringValue() = scheme + ":"
)
or
// propagate through various string transformations
exists(string stringop, DataFlow::CallNode c |
stringop = "Map" or
stringop.matches("Replace%") or
stringop.matches("To%") or
stringop.matches("Trim%")
|
c.getTarget().hasQualifiedName("strings", stringop) and
c.getAnArgument() = g.getANode() and
result = schemeCheck(globalValueNumber(c), scheme)
)
}
/**
* Gets a scheme that `g`, which is checked against at least one scheme, is not checked against.
*/
DangerousScheme getAMissingScheme(GVN g) {
exists(schemeCheck(g, _)) and
not exists(schemeCheck(g, result))
}
from GVN g
select schemeCheck(g, "javascript"),
"This check does not consider " + strictconcat(getAMissingScheme(g), " and ") + "."