@@ -25,13 +25,13 @@ module ReflectedXss {
25
25
* is to prevent us from flagging plain-text or JSON responses as vulnerable.
26
26
*/
27
27
class HttpResponseSink extends Sink instanceof Http:: ResponseSendArgument {
28
- HttpResponseSink ( ) { not exists ( getANonHtmlHeaderDefinition ( this ) ) }
28
+ HttpResponseSink ( ) { not exists ( getAXssSafeHeaderDefinition ( this ) ) }
29
29
}
30
30
31
31
/**
32
- * Gets a HeaderDefinition that defines a non-html content-type for `send`.
32
+ * DEPRECATED: Gets a HeaderDefinition that defines a non-html content-type for `send`.
33
33
*/
34
- Http:: HeaderDefinition getANonHtmlHeaderDefinition ( Http:: ResponseSendArgument send ) {
34
+ deprecated Http:: HeaderDefinition getANonHtmlHeaderDefinition ( Http:: ResponseSendArgument send ) {
35
35
exists ( Http:: RouteHandler h |
36
36
send .getRouteHandler ( ) = h and
37
37
result = nonHtmlContentTypeHeader ( h )
@@ -42,13 +42,49 @@ module ReflectedXss {
42
42
}
43
43
44
44
/**
45
- * Holds if `h` may send a response with a content type other than HTML.
45
+ * DEPRECATED: Holds if `h` may send a response with a content type other than HTML.
46
46
*/
47
- Http:: HeaderDefinition nonHtmlContentTypeHeader ( Http:: RouteHandler h ) {
47
+ deprecated Http:: HeaderDefinition nonHtmlContentTypeHeader ( Http:: RouteHandler h ) {
48
48
result = h .getAResponseHeader ( "content-type" ) and
49
49
not exists ( string tp | result .defines ( "content-type" , tp ) | tp .regexpMatch ( "(?i).*html.*" ) )
50
50
}
51
51
52
+ /**
53
+ * Gets a HeaderDefinition that defines a XSS safe content-type for `send`.
54
+ */
55
+ Http:: HeaderDefinition getAXssSafeHeaderDefinition ( Http:: ResponseSendArgument send ) {
56
+ exists ( Http:: RouteHandler h |
57
+ send .getRouteHandler ( ) = h and
58
+ result = xssSafeContentTypeHeader ( h )
59
+ |
60
+ // The HeaderDefinition affects a response sent at `send`.
61
+ headerAffects ( result , send )
62
+ )
63
+ }
64
+
65
+ /**
66
+ * Gets a content-type that may lead to javascript code being executed in the browser.
67
+ * ref: https://portswigger.net/web-security/cross-site-scripting/cheat-sheet#content-types
68
+ */
69
+ string xssUnsafeContentType ( ) {
70
+ result =
71
+ [
72
+ "text/html" , "application/xhtml+xml" , "application/xml" , "text/xml" , "image/svg+xml" ,
73
+ "text/xsl" , "application/vnd.wap.xhtml+xml" , "text/rdf" , "application/rdf+xml" ,
74
+ "application/mathml+xml" , "text/vtt" , "text/cache-manifest"
75
+ ]
76
+ }
77
+
78
+ /**
79
+ * Holds if `h` may send a response with a content type that is safe for XSS.
80
+ */
81
+ Http:: HeaderDefinition xssSafeContentTypeHeader ( Http:: RouteHandler h ) {
82
+ result = h .getAResponseHeader ( "content-type" ) and
83
+ not exists ( string tp | result .defines ( "content-type" , tp ) |
84
+ tp .toLowerCase ( ) .matches ( xssUnsafeContentType ( ) + "%" )
85
+ )
86
+ }
87
+
52
88
/**
53
89
* Holds if a header set in `header` is likely to affect a response sent at `sender`.
54
90
*/
@@ -61,6 +97,7 @@ module ReflectedXss {
61
97
// There is no dominating header, and `header` is non-local.
62
98
not isLocalHeaderDefinition ( header ) and
63
99
not exists ( Http:: HeaderDefinition dominatingHeader |
100
+ dominatingHeader .getAHeaderName ( ) = "content-type" and
64
101
dominatingHeader .getBasicBlock ( ) .( ReachableBasicBlock ) .dominates ( sender .getBasicBlock ( ) )
65
102
)
66
103
)
0 commit comments