1
1
/**
2
- * @name Inclusion of untrusted functionality by a HTML element .
3
- * @description Including untrusted functionality by a HTML element
4
- * opens up for potential man-in- the-middle attacks .
2
+ * @name Inclusion of functionality from untrusted source .
3
+ * @description Including functionality from an untrusted source may allow
4
+ * an attacker to control the functionality and execute arbitrary code .
5
5
* @kind problem
6
6
* @problem.severity warning
7
- * @security-severity 8.1
7
+ * @security-severity 6.0
8
8
* @precision high
9
9
* @id js/functionality-from-untrusted-source
10
10
* @tags security
11
11
* external/cwe/cwe-830
12
12
*/
13
13
14
14
import javascript
15
- import semmle.javascript.HTML
16
- import semmle.javascript.dataflow.TaintTracking
17
15
18
- module Generic {
19
- /** A `CallNode` that creates an element of kind `name`. */
20
- predicate isCreateElementNode ( DataFlow:: CallNode call , string name ) {
21
- call = DataFlow:: globalVarRef ( "document" ) .getAMethodCall ( "createElement" ) and
22
- call .getArgument ( 0 ) .getStringValue ( ) .toLowerCase ( ) = name
23
- }
24
-
25
- /**
26
- * A `createElement` call that creates a `<script ../>` element which never
27
- * has its `integrity` attribute set locally.
28
- */
29
- predicate isCreateScriptNodeWoIntegrityCheck ( DataFlow:: CallNode createCall ) {
30
- isCreateElementNode ( createCall , "script" ) and
31
- not exists ( createCall .getAPropertyWrite ( "integrity" ) )
32
- }
33
-
34
- /** A location that adds a reference to an untrusted source. */
35
- abstract class AddsUntrustedUrl extends Locatable {
36
- /** Gets an explanation why this source is untrusted. */
37
- abstract string getProblem ( ) ;
38
- }
16
+ /** A location that adds a reference to an untrusted source. */
17
+ abstract class AddsUntrustedUrl extends Locatable {
18
+ /** Gets an explanation why this source is untrusted. */
19
+ abstract string getProblem ( ) ;
39
20
}
40
21
41
22
module StaticCreation {
23
+ /** Holds if `host` is an alias of localhost. */
42
24
bindingset [ host]
43
25
predicate isLocalhostPrefix ( string host ) {
44
26
host .toLowerCase ( )
@@ -47,15 +29,15 @@ module StaticCreation {
47
29
] )
48
30
}
49
31
50
- /** A path that is vulnerable to a MITM attack. */
32
+ /** Holds if `url` is a url that is vulnerable to a MITM attack. */
51
33
bindingset [ url]
52
34
predicate isUntrustedSourceUrl ( string url ) {
53
35
exists ( string hostPath | hostPath = url .regexpCapture ( "(?i)http://(.*)" , 1 ) |
54
36
not isLocalhostPrefix ( hostPath )
55
37
)
56
38
}
57
39
58
- /** A path that needs an integrity check - even with https. */
40
+ /** Holds if `url` refers to a CDN that needs an integrity check - even with https. */
59
41
bindingset [ url]
60
42
predicate isCdnUrlWithCheckingRequired ( string url ) {
61
43
// Some CDN URLs are required to have an integrity attribute. We only add CDNs to that list
@@ -68,47 +50,56 @@ module StaticCreation {
68
50
}
69
51
70
52
/** A script element that refers to untrusted content. */
71
- class ScriptElementWithUntrustedContent extends Generic :: AddsUntrustedUrl , HTML:: ScriptElement {
53
+ class ScriptElementWithUntrustedContent extends AddsUntrustedUrl instanceof HTML:: ScriptElement {
72
54
ScriptElementWithUntrustedContent ( ) {
73
- not exists ( string digest | not digest = "" | this .getIntegrityDigest ( ) = digest ) and
74
- isUntrustedSourceUrl ( this .getSourcePath ( ) )
55
+ not exists ( string digest | not digest = "" | super .getIntegrityDigest ( ) = digest ) and
56
+ isUntrustedSourceUrl ( super .getSourcePath ( ) )
75
57
}
76
58
77
59
override string getProblem ( ) {
78
- result = "script elements should use an 'https:' URL and/or use the integrity attribute "
60
+ result = "HTML script element loaded using unencrypted connection. "
79
61
}
80
62
}
81
63
82
64
/** A script element that refers to untrusted content. */
83
- class CDNScriptElementWithUntrustedContent extends Generic :: AddsUntrustedUrl , HTML:: ScriptElement {
65
+ class CDNScriptElementWithUntrustedContent extends AddsUntrustedUrl , HTML:: ScriptElement {
84
66
CDNScriptElementWithUntrustedContent ( ) {
85
67
not exists ( string digest | not digest = "" | this .getIntegrityDigest ( ) = digest ) and
86
68
isCdnUrlWithCheckingRequired ( this .getSourcePath ( ) )
87
69
}
88
70
89
71
override string getProblem ( ) {
90
72
result =
91
- "script elements that depend on this CDN should use an 'https:' URL and use the integrity attribute "
73
+ "Script loaded from content delivery network with no integrity check. "
92
74
}
93
75
}
94
76
95
77
/** An iframe element that includes untrusted content. */
96
- class IframeElementWithUntrustedContent extends HTML:: IframeElement , Generic :: AddsUntrustedUrl {
97
- IframeElementWithUntrustedContent ( ) { isUntrustedSourceUrl ( this .getSourcePath ( ) ) }
78
+ class IframeElementWithUntrustedContent extends AddsUntrustedUrl instanceof HTML:: IframeElement {
79
+ IframeElementWithUntrustedContent ( ) { isUntrustedSourceUrl ( super .getSourcePath ( ) ) }
98
80
99
- override string getProblem ( ) { result = "iframe elements should use an 'https:' URL " }
81
+ override string getProblem ( ) { result = "HTML iframe element loaded using unencrypted connection. " }
100
82
}
101
83
}
102
84
103
85
module DynamicCreation {
104
- import DataFlow:: TypeTracker
86
+ /** Holds if `call` creates a tag of kind `name`. */
87
+ predicate isCreateElementNode ( DataFlow:: CallNode call , string name ) {
88
+ call = DataFlow:: globalVarRef ( "document" ) .getAMethodCall ( "createElement" ) and
89
+ call .getArgument ( 0 ) .getStringValue ( ) .toLowerCase ( ) = name
90
+ }
105
91
106
- predicate isUnsafeSourceLiteral ( DataFlow:: Node source ) {
107
- exists ( StringLiteral s | source = s .flow ( ) | s .getValue ( ) .regexpMatch ( "(?i)http:.*" ) )
92
+ /**
93
+ * Holds if `createCall` creates a `<script ../>` element which never
94
+ * has its `integrity` attribute set locally.
95
+ */
96
+ predicate isCreateScriptNodeWoIntegrityCheck ( DataFlow:: CallNode createCall ) {
97
+ isCreateElementNode ( createCall , "script" ) and
98
+ not exists ( createCall .getAPropertyWrite ( "integrity" ) )
108
99
}
109
100
110
101
DataFlow:: Node urlTrackedFromUnsafeSourceLiteral ( DataFlow:: TypeTracker t ) {
111
- t .start ( ) and isUnsafeSourceLiteral ( result )
102
+ t .start ( ) and result . getStringValue ( ) . regexpMatch ( "(?i)http:.*" )
112
103
or
113
104
exists ( DataFlow:: TypeTracker t2 , DataFlow:: Node prev |
114
105
prev = urlTrackedFromUnsafeSourceLiteral ( t2 )
@@ -137,16 +128,16 @@ module DynamicCreation {
137
128
predicate isAssignedToSrcAttribute ( string name , DataFlow:: Node sink ) {
138
129
exists ( DataFlow:: CallNode createElementCall |
139
130
name = "script" and
140
- Generic :: isCreateScriptNodeWoIntegrityCheck ( createElementCall ) and
131
+ isCreateScriptNodeWoIntegrityCheck ( createElementCall ) and
141
132
sink = createElementCall .getAPropertyWrite ( "src" ) .getRhs ( )
142
133
or
143
134
name = "iframe" and
144
- Generic :: isCreateElementNode ( createElementCall , "iframe" ) and
135
+ isCreateElementNode ( createElementCall , "iframe" ) and
145
136
sink = createElementCall .getAPropertyWrite ( "src" ) .getRhs ( )
146
137
)
147
138
}
148
139
149
- class IframeOrScriptSrcAssignment extends Expr , Generic :: AddsUntrustedUrl {
140
+ class IframeOrScriptSrcAssignment extends AddsUntrustedUrl {
150
141
string name ;
151
142
152
143
IframeOrScriptSrcAssignment ( ) {
@@ -157,13 +148,10 @@ module DynamicCreation {
157
148
}
158
149
159
150
override string getProblem ( ) {
160
- name = "script" and
161
- result = "script elements should use an 'https:' URL and/or use the integrity attribute"
162
- or
163
- name = "iframe" and result = "iframe elements should use an 'https:' URL"
151
+ result = "HTML " + name + " element loaded using unencrypted connection."
164
152
}
165
153
}
166
154
}
167
155
168
- from Generic :: AddsUntrustedUrl s
169
- select s , "HTML-element uses untrusted content (" + s .getProblem ( ) + ")"
156
+ from AddsUntrustedUrl s
157
+ select s , s .getProblem ( )
0 commit comments