@@ -16,14 +16,20 @@ module CleartextLogging {
1616 /** Gets a string that describes the type of this data flow source. */
1717 abstract string describe ( ) ;
1818
19- abstract DataFlow:: FlowLabel getLabel ( ) ;
19+ /**
20+ * DEPRECATED. Overriding this predicate no longer has any effect.
21+ */
22+ deprecated DataFlow:: FlowLabel getLabel ( ) { result .isTaint ( ) }
2023 }
2124
2225 /**
2326 * A data flow sink for clear-text logging of sensitive information.
2427 */
2528 abstract class Sink extends DataFlow:: Node {
26- DataFlow:: FlowLabel getLabel ( ) { result .isTaint ( ) }
29+ /**
30+ * DEPRECATED. Overriding this predicate no longer has any effect.
31+ */
32+ deprecated DataFlow:: FlowLabel getLabel ( ) { result .isTaint ( ) }
2733 }
2834
2935 /**
@@ -103,29 +109,28 @@ module CleartextLogging {
103109 abstract private class NonCleartextPassword extends DataFlow:: Node { }
104110
105111 /**
106- * An object with a property that may contain password information
107- *
108- * This is a source since `console.log(obj)` will show the properties of `obj`.
112+ * A value stored in a property that may contain password information
109113 */
110114 private class ObjectPasswordPropertySource extends DataFlow:: ValueNode , Source {
111115 string name ;
112116
113117 ObjectPasswordPropertySource ( ) {
114118 exists ( DataFlow:: PropWrite write |
119+ write .getPropertyName ( ) = name and
115120 name .regexpMatch ( maybePassword ( ) ) and
116121 not name .regexpMatch ( notSensitiveRegexp ( ) ) and
117- write = this . ( DataFlow :: SourceNode ) . getAPropertyWrite ( name ) and
122+ this = write . getRhs ( ) and
118123 // avoid safe values assigned to presumably unsafe names
119- not write . getRhs ( ) instanceof NonCleartextPassword
124+ not this instanceof NonCleartextPassword
120125 )
121126 }
122127
123128 override string describe ( ) { result = "an access to " + name }
124-
125- override DataFlow:: FlowLabel getLabel ( ) { result .isTaint ( ) }
126129 }
127130
128- /** An access to a variable or property that might contain a password. */
131+ /**
132+ * An access to a variable or property that might contain a password.
133+ */
129134 private class ReadPasswordSource extends DataFlow:: ValueNode , Source {
130135 string name ;
131136
@@ -147,8 +152,6 @@ module CleartextLogging {
147152 }
148153
149154 override string describe ( ) { result = "an access to " + name }
150-
151- override DataFlow:: FlowLabel getLabel ( ) { result .isTaint ( ) }
152155 }
153156
154157 /** A call that might return a password. */
@@ -161,17 +164,35 @@ module CleartextLogging {
161164 }
162165
163166 override string describe ( ) { result = "a call to " + name }
164-
165- override DataFlow:: FlowLabel getLabel ( ) { result .isTaint ( ) }
166167 }
167168
168169 /** An access to the sensitive object `process.env`. */
169170 class ProcessEnvSource extends Source {
170171 ProcessEnvSource ( ) { this = NodeJSLib:: process ( ) .getAPropertyRead ( "env" ) }
171172
172173 override string describe ( ) { result = "process environment" }
174+ }
173175
174- override DataFlow:: FlowLabel getLabel ( ) { result .isTaint ( ) }
176+ /** Gets a data flow node referring to `process.env`. */
177+ private DataFlow:: SourceNode processEnv ( DataFlow:: TypeTracker t ) {
178+ t .start ( ) and
179+ result instanceof ProcessEnvSource
180+ or
181+ exists ( DataFlow:: TypeTracker t2 | result = processEnv ( t2 ) .track ( t2 , t ) )
182+ }
183+
184+ /** Gets a data flow node referring to `process.env`. */
185+ DataFlow:: SourceNode processEnv ( ) { result = processEnv ( DataFlow:: TypeTracker:: end ( ) ) }
186+
187+ /**
188+ * A property access on `process.env`, seen as a barrier.
189+ */
190+ private class SafeEnvironmentVariableBarrier extends Barrier instanceof DataFlow:: PropRead {
191+ SafeEnvironmentVariableBarrier ( ) {
192+ this = processEnv ( ) .getAPropertyRead ( ) and
193+ // If the name is known, it should not be sensitive
194+ not nameIndicatesSensitiveData ( this .getPropertyName ( ) , _)
195+ }
175196 }
176197
177198 /**
@@ -183,26 +204,10 @@ module CleartextLogging {
183204 succ .( DataFlow:: PropRead ) .getBase ( ) = pred
184205 }
185206
186- private class PropReadAsBarrier extends Barrier {
187- PropReadAsBarrier ( ) {
188- this = any ( DataFlow:: PropRead read ) .getBase ( ) and
189- // the 'foo' in 'foo.bar()' may have flow, we only want to suppress plain property reads
190- not this = any ( DataFlow:: MethodCallNode call ) .getReceiver ( ) and
191- // do not block custom taint steps from this node
192- not isAdditionalTaintStep ( this , _)
193- }
194- }
195-
196207 /**
197208 * Holds if the edge `src` -> `trg` is an additional taint-step for clear-text logging of sensitive information.
198209 */
199210 predicate isAdditionalTaintStep ( DataFlow:: Node src , DataFlow:: Node trg ) {
200- // A taint propagating data flow edge through objects: a tainted write taints the entire object.
201- exists ( DataFlow:: PropWrite write |
202- write .getRhs ( ) = src and
203- trg .( DataFlow:: SourceNode ) .flowsTo ( write .getBase ( ) )
204- )
205- or
206211 // A property-copy step,
207212 // dst[x] = src[x]
208213 // dst[x] = JSON.stringify(src[x])
@@ -218,7 +223,7 @@ module CleartextLogging {
218223 not exists ( read .getPropertyName ( ) ) and
219224 not isFilteredPropertyName ( read .getPropertyNameExpr ( ) .flow ( ) .getALocalSource ( ) ) and
220225 src = read .getBase ( ) and
221- trg = write .getBase ( ) .getALocalSource ( )
226+ trg = write .getBase ( ) .getPostUpdateNode ( )
222227 )
223228 or
224229 // Taint through the arguments object.
0 commit comments