11/**
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 .
55 * @kind problem
66 * @problem.severity warning
7- * @security-severity 8.1
7+ * @security-severity 6.0
88 * @precision high
99 * @id js/functionality-from-untrusted-source
1010 * @tags security
1111 * external/cwe/cwe-830
1212 */
1313
1414import javascript
15- import semmle.javascript.HTML
16- import semmle.javascript.dataflow.TaintTracking
1715
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 ( ) ;
3920}
4021
4122module StaticCreation {
23+ /** Holds if `host` is an alias of localhost. */
4224 bindingset [ host]
4325 predicate isLocalhostPrefix ( string host ) {
4426 host .toLowerCase ( )
@@ -47,15 +29,15 @@ module StaticCreation {
4729 ] )
4830 }
4931
50- /** A path that is vulnerable to a MITM attack. */
32+ /** Holds if `url` is a url that is vulnerable to a MITM attack. */
5133 bindingset [ url]
5234 predicate isUntrustedSourceUrl ( string url ) {
5335 exists ( string hostPath | hostPath = url .regexpCapture ( "(?i)http://(.*)" , 1 ) |
5436 not isLocalhostPrefix ( hostPath )
5537 )
5638 }
5739
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. */
5941 bindingset [ url]
6042 predicate isCdnUrlWithCheckingRequired ( string url ) {
6143 // Some CDN URLs are required to have an integrity attribute. We only add CDNs to that list
@@ -68,47 +50,56 @@ module StaticCreation {
6850 }
6951
7052 /** A script element that refers to untrusted content. */
71- class ScriptElementWithUntrustedContent extends Generic :: AddsUntrustedUrl , HTML:: ScriptElement {
53+ class ScriptElementWithUntrustedContent extends AddsUntrustedUrl instanceof HTML:: ScriptElement {
7254 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 ( ) )
7557 }
7658
7759 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. "
7961 }
8062 }
8163
8264 /** A script element that refers to untrusted content. */
83- class CDNScriptElementWithUntrustedContent extends Generic :: AddsUntrustedUrl , HTML:: ScriptElement {
65+ class CDNScriptElementWithUntrustedContent extends AddsUntrustedUrl , HTML:: ScriptElement {
8466 CDNScriptElementWithUntrustedContent ( ) {
8567 not exists ( string digest | not digest = "" | this .getIntegrityDigest ( ) = digest ) and
8668 isCdnUrlWithCheckingRequired ( this .getSourcePath ( ) )
8769 }
8870
8971 override string getProblem ( ) {
9072 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. "
9274 }
9375 }
9476
9577 /** 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 ( ) ) }
9880
99- override string getProblem ( ) { result = "iframe elements should use an 'https:' URL " }
81+ override string getProblem ( ) { result = "HTML iframe element loaded using unencrypted connection. " }
10082 }
10183}
10284
10385module 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+ }
10591
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" ) )
10899 }
109100
110101 DataFlow:: Node urlTrackedFromUnsafeSourceLiteral ( DataFlow:: TypeTracker t ) {
111- t .start ( ) and isUnsafeSourceLiteral ( result )
102+ t .start ( ) and result . getStringValue ( ) . regexpMatch ( "(?i)http:.*" )
112103 or
113104 exists ( DataFlow:: TypeTracker t2 , DataFlow:: Node prev |
114105 prev = urlTrackedFromUnsafeSourceLiteral ( t2 )
@@ -137,16 +128,16 @@ module DynamicCreation {
137128 predicate isAssignedToSrcAttribute ( string name , DataFlow:: Node sink ) {
138129 exists ( DataFlow:: CallNode createElementCall |
139130 name = "script" and
140- Generic :: isCreateScriptNodeWoIntegrityCheck ( createElementCall ) and
131+ isCreateScriptNodeWoIntegrityCheck ( createElementCall ) and
141132 sink = createElementCall .getAPropertyWrite ( "src" ) .getRhs ( )
142133 or
143134 name = "iframe" and
144- Generic :: isCreateElementNode ( createElementCall , "iframe" ) and
135+ isCreateElementNode ( createElementCall , "iframe" ) and
145136 sink = createElementCall .getAPropertyWrite ( "src" ) .getRhs ( )
146137 )
147138 }
148139
149- class IframeOrScriptSrcAssignment extends Expr , Generic :: AddsUntrustedUrl {
140+ class IframeOrScriptSrcAssignment extends AddsUntrustedUrl {
150141 string name ;
151142
152143 IframeOrScriptSrcAssignment ( ) {
@@ -157,13 +148,10 @@ module DynamicCreation {
157148 }
158149
159150 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."
164152 }
165153 }
166154}
167155
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