This repository was archived by the owner on Jan 5, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 128
Expand file tree
/
Copy pathXss.qll
More file actions
106 lines (96 loc) · 3.81 KB
/
Xss.qll
File metadata and controls
106 lines (96 loc) · 3.81 KB
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
/**
* Provides classes and predicates used by the XSS queries.
*/
import go
/** Provides classes and predicates shared between the XSS queries. */
module SharedXss {
/** A data flow source for XSS vulnerabilities. */
abstract class Source extends DataFlow::Node { }
/** A data flow sink for XSS vulnerabilities. */
abstract class Sink extends DataFlow::Node {
/**
* Gets the kind of vulnerability to report in the alert message.
*
* Defaults to `Cross-site scripting`, but may be overriden for sinks
* that do not allow script injection, but injection of other undesirable HTML elements.
*/
string getVulnerabilityKind() { result = "Cross-site scripting" }
}
/** A sanitizer for XSS vulnerabilities. */
abstract class Sanitizer extends DataFlow::Node { }
/** A sanitizer guard for XSS vulnerabilities. */
abstract class SanitizerGuard extends DataFlow::BarrierGuard { }
/**
* An expression that is sent as part of an HTTP response body, considered as an
* XSS sink.
*
* We exclude cases where the route handler sets either an unknown content type or
* a content type that does not (case-insensitively) contain the string "html". This
* is to prevent us from flagging plain-text or JSON responses as vulnerable.
*/
class HttpResponseBodySink extends Sink, HTTP::ResponseBody {
HttpResponseBodySink() { not nonHtmlContentType(this) }
}
/**
* Holds if `body` may send a response with a content type other than HTML.
*/
private predicate nonHtmlContentType(HTTP::ResponseBody body) {
not htmlTypeSpecified(body) and
(
exists(body.getAContentType())
or
exists(body.getAContentTypeNode())
or
exists(DataFlow::CallNode call | call.getTarget().hasQualifiedName("fmt", "Fprintf") |
body = call.getAnArgument() and
// checks that the format value does not start with (ignoring whitespace as defined by
// https://mimesniff.spec.whatwg.org/#whitespace-byte):
// - '<', which could lead to an HTML content type being detected, or
// - '%', which could be a format string.
call.getArgument(1).getStringValue().regexpMatch("(?s)[\\t\\n\\x0c\\r ]*+[^<%].*")
)
or
exists(DataFlow::Node pred | body = pred.getASuccessor*() |
// data starting with a character other than `<` (ignoring whitespace as defined by
// https://mimesniff.spec.whatwg.org/#whitespace-byte) cannot cause an HTML content type to
// be detected.
pred.getStringValue().regexpMatch("(?s)[\\t\\n\\x0c\\r ]*+[^<].*")
)
)
}
/**
* Holds if `body` specifies the response's content type to be HTML.
*/
private predicate htmlTypeSpecified(HTTP::ResponseBody body) {
body.getAContentType().regexpMatch("(?i).*html.*")
}
/**
* A JSON marshaler, acting to sanitize a possible XSS vulnerability because the
* marshaled value is very unlikely to be returned as an HTML content-type.
*/
class JsonMarshalSanitizer extends Sanitizer {
JsonMarshalSanitizer() {
exists(MarshalingFunction mf | mf.getFormat() = "JSON" |
this = mf.getOutput().getNode(mf.getACall())
)
}
}
/**
* A regexp replacement involving an HTML meta-character, or a call to an escape
* function, viewed as a sanitizer for XSS vulnerabilities.
*
* The XSS queries do not attempt to reason about correctness or completeness of sanitizers,
* so any such call stops taint propagation.
*/
class MetacharEscapeSanitizer extends Sanitizer, DataFlow::CallNode {
MetacharEscapeSanitizer() {
exists(Function f | f = this.getCall().getTarget() |
f.(RegexpReplaceFunction).getRegexp(this).getPattern().regexpMatch(".*['\"&<>].*")
or
f instanceof HtmlEscapeFunction
or
f instanceof JsEscapeFunction
)
}
}
}