11/**
2- * Provides a taint-tracking configuration for tracking user-controlled objects flowing
3- * into a vulnerable `extends` call.
2+ * Provides a taint-tracking configuration for tracking
3+ * user-controlled objects flowing into a vulnerable `extends` call.
4+ *
5+ * Note, for performance reasons: only import this file if
6+ * `PrototypePollution::Configuration` is needed, otherwise
7+ * `PrototypePollutionCustomizations` should be imported instead.
48 */
59
610import javascript
@@ -9,52 +13,7 @@ import semmle.javascript.dependencies.Dependencies
913import semmle.javascript.dependencies.SemVer
1014
1115module PrototypePollution {
12- /**
13- * Label for wrappers around tainted objects, that is, objects that are
14- * not completely user-controlled, but contain a user-controlled object.
15- *
16- * For example, `options` below is is a tainted wrapper, but is not itself
17- * a tainted object:
18- * ```
19- * let options = {
20- * prefs: {
21- * locale: req.query.locale
22- * }
23- * }
24- * ```
25- */
26- module TaintedObjectWrapper {
27- private class TaintedObjectWrapper extends DataFlow:: FlowLabel {
28- TaintedObjectWrapper ( ) { this = "tainted-object-wrapper" }
29- }
30-
31- TaintedObjectWrapper label ( ) { any ( ) }
32- }
33-
34- /**
35- * A data flow source for prototype pollution.
36- */
37- abstract class Source extends DataFlow:: Node {
38- /**
39- * Gets the type of data coming from this source.
40- */
41- abstract DataFlow:: FlowLabel getAFlowLabel ( ) ;
42- }
43-
44- /**
45- * A data flow sink for prototype pollution.
46- */
47- abstract class Sink extends DataFlow:: Node {
48- /**
49- * Gets the type of data that can taint this sink.
50- */
51- abstract DataFlow:: FlowLabel getAFlowLabel ( ) ;
52-
53- /**
54- * Gets the dependency that defines this sink.
55- */
56- abstract Dependency getDependency ( ) ;
57- }
16+ import PrototypePollutionCustomizations:: PrototypePollution
5817
5918 /**
6019 * A taint tracking configuration for user-controlled objects flowing into deep `extend` calls,
@@ -89,94 +48,4 @@ module PrototypePollution {
8948 node instanceof TaintedObject:: SanitizerGuard
9049 }
9150 }
92-
93- /**
94- * A user-controlled string value, as a source of prototype pollution.
95- *
96- * Note that values from this type of source will need to flow through a `JSON.parse` call
97- * in order to be flagged for prototype pollution.
98- */
99- private class RemoteFlowAsSource extends Source {
100- RemoteFlowAsSource ( ) { this instanceof RemoteFlowSource }
101-
102- override DataFlow:: FlowLabel getAFlowLabel ( ) { result = DataFlow:: FlowLabel:: data ( ) }
103- }
104-
105- /**
106- * A source of user-controlled objects.
107- */
108- private class TaintedObjectSource extends Source {
109- TaintedObjectSource ( ) { this instanceof TaintedObject:: Source }
110-
111- override DataFlow:: FlowLabel getAFlowLabel ( ) { result = TaintedObject:: label ( ) }
112- }
113-
114- class DeepExtendSink extends Sink {
115- ExtendCall call ;
116-
117- Dependency dependency ;
118-
119- DeepExtendSink ( ) {
120- this = call .getASourceOperand ( ) and
121- isVulnerableDeepExtendCall ( call , dependency )
122- }
123-
124- override DataFlow:: FlowLabel getAFlowLabel ( ) {
125- result = TaintedObject:: label ( )
126- or
127- result = TaintedObjectWrapper:: label ( )
128- }
129-
130- override Dependency getDependency ( ) { result = dependency }
131- }
132-
133- /**
134- * Holds if `call` is vulnerable to prototype pollution because the callee is defined by `dep`.
135- */
136- predicate isVulnerableDeepExtendCall ( ExtendCall call , Dependency dep ) {
137- call .isDeep ( ) and
138- (
139- call = DataFlow:: dependencyModuleImport ( dep ) .getAMemberCall ( _) or
140- call = DataFlow:: dependencyModuleImport ( dep ) .getACall ( )
141- ) and
142- exists ( DependencySemVer version , string id | dep .info ( id , version ) |
143- id = "assign-deep" and
144- version .maybeBefore ( "0.4.7" )
145- or
146- id = "deep"
147- or
148- id = "deep-extend" and
149- version .maybeBefore ( "0.5.1" )
150- or
151- id = "defaults-deep" and
152- version .maybeBefore ( "0.2.4" )
153- or
154- id = "extend" and
155- ( version .maybeBefore ( "2.0.2" ) or version .maybeBetween ( "3.0.0" , "3.0.2" ) )
156- or
157- id = "extend2"
158- or
159- id = "js-extend"
160- or
161- id = "just-extend" and
162- version .maybeBefore ( "4.0.1" )
163- or
164- id = "lodash" + any ( string s ) and
165- version .maybeBefore ( "4.17.12" )
166- or
167- id = "merge" and
168- version .maybeBefore ( "1.2.1" )
169- or
170- id = "merge-deep" and
171- version .maybeBefore ( "3.0.1" )
172- or
173- id = "merge-options" and
174- version .maybeBefore ( "1.0.1" )
175- or
176- id = "node.extend" and
177- ( version .maybeBefore ( "1.1.7" ) or version .maybeBetween ( "2.0.0" , "2.0.1" ) )
178- or
179- id = "smart-extend"
180- )
181- }
18251}
0 commit comments