@@ -69,22 +69,53 @@ module UntrustedToAllowOriginHeaderConfig implements DataFlow::ConfigSig {
6969 predicate isSink ( DataFlow:: Node sink ) { isSinkHW ( sink , _) }
7070}
7171
72+ module UntrustedToAllowOriginConfigConfig implements DataFlow:: ConfigSig {
73+ predicate isSource ( DataFlow:: Node source ) { source instanceof UntrustedFlowSource }
74+
75+ additional predicate isSinkWrite ( DataFlow:: Node sink , GinCors:: AllowOriginsWrite w ) { sink = w }
76+
77+ predicate isSink ( DataFlow:: Node sink ) { isSinkWrite ( sink , _) }
78+ }
79+
7280/**
7381 * Tracks taint flowfor reasoning about when an `UntrustedFlowSource` flows to
7482 * a `HeaderWrite` that writes an `Access-Control-Allow-Origin` header's value.
7583 */
7684module UntrustedToAllowOriginHeaderFlow = TaintTracking:: Global< UntrustedToAllowOriginHeaderConfig > ;
7785
86+ /**
87+ * Tracks taint flowfor reasoning about when an `UntrustedFlowSource` flows to
88+ * a `AllowOriginsWrite` that writes an `Access-Control-Allow-Origin` header's value.
89+ */
90+ module UntrustedToAllowOriginConfigFlow = TaintTracking:: Global< UntrustedToAllowOriginConfigConfig > ;
91+
7892/**
7993 * Holds if the provided `allowOriginHW` HeaderWrite's parent ResponseWriter
8094 * also has another HeaderWrite that sets a `Access-Control-Allow-Credentials`
8195 * header to `true`.
8296 */
83- predicate allowCredentialsIsSetToTrue ( AllowOriginHeaderWrite allowOriginHW ) {
97+ predicate allowCredentialsIsSetToTrue ( DataFlow :: ExprNode allowOriginHW ) {
8498 exists ( AllowCredentialsHeaderWrite allowCredentialsHW |
8599 allowCredentialsHW .getHeaderValue ( ) .toLowerCase ( ) = "true"
86100 |
87- allowOriginHW .getResponseWriter ( ) = allowCredentialsHW .getResponseWriter ( )
101+ allowOriginHW .( AllowOriginHeaderWrite ) .getResponseWriter ( ) =
102+ allowCredentialsHW .getResponseWriter ( )
103+ )
104+ or
105+ exists ( GinCors:: AllowCredentialsWrite allowCredentialsGin |
106+ allowCredentialsGin .getExpr ( ) .getBoolValue ( ) = true
107+ |
108+ allowCredentialsGin .getConfig ( ) = allowOriginHW .( GinCors:: AllowOriginsWrite ) .getConfig ( ) and
109+ not exists ( GinCors:: AllowAllOriginsWrite allowAllOrigins |
110+ allowAllOrigins .getExpr ( ) .getBoolValue ( ) = true and
111+ allowCredentialsGin .getConfig ( ) = allowAllOrigins .getConfig ( )
112+ )
113+ or
114+ allowCredentialsGin .getBase ( ) = allowOriginHW .( GinCors:: AllowOriginsWrite ) .getBase ( ) and
115+ not exists ( GinCors:: AllowAllOriginsWrite allowAllOrigins |
116+ allowAllOrigins .getExpr ( ) .getBoolValue ( ) = true and
117+ allowCredentialsGin .getBase ( ) = allowAllOrigins .getBase ( )
118+ )
88119 )
89120}
90121
@@ -93,10 +124,13 @@ predicate allowCredentialsIsSetToTrue(AllowOriginHeaderWrite allowOriginHW) {
93124 * UntrustedFlowSource.
94125 * The `message` parameter is populated with the warning message to be returned by the query.
95126 */
96- predicate flowsFromUntrustedToAllowOrigin ( AllowOriginHeaderWrite allowOriginHW , string message ) {
127+ predicate flowsFromUntrustedToAllowOrigin ( DataFlow :: ExprNode allowOriginHW , string message ) {
97128 exists ( DataFlow:: Node sink |
98129 UntrustedToAllowOriginHeaderFlow:: flowTo ( sink ) and
99130 UntrustedToAllowOriginHeaderConfig:: isSinkHW ( sink , allowOriginHW )
131+ or
132+ UntrustedToAllowOriginConfigFlow:: flowTo ( sink ) and
133+ UntrustedToAllowOriginConfigConfig:: isSinkWrite ( sink , allowOriginHW )
100134 |
101135 message =
102136 headerAllowOrigin ( ) + " header is set to a user-defined value, and " +
@@ -108,11 +142,23 @@ predicate flowsFromUntrustedToAllowOrigin(AllowOriginHeaderWrite allowOriginHW,
108142 * Holds if the provided `allowOriginHW` HeaderWrite is for a `Access-Control-Allow-Origin`
109143 * header and the value is set to `null`.
110144 */
111- predicate allowOriginIsNull ( AllowOriginHeaderWrite allowOriginHW , string message ) {
112- allowOriginHW .getHeaderValue ( ) .toLowerCase ( ) = "null" and
145+ predicate allowOriginIsNull ( DataFlow:: ExprNode allowOriginHW , string message ) {
146+ allowOriginHW .( AllowOriginHeaderWrite ) .getHeaderValue ( ) .toLowerCase ( ) = "null" and
147+ message =
148+ headerAllowOrigin ( ) + " header is set to `" +
149+ allowOriginHW .( AllowOriginHeaderWrite ) .getHeaderValue ( ) + "`, and " + headerAllowCredentials ( )
150+ + " is set to `true`"
151+ or
152+ allowOriginHW
153+ .( GinCors:: AllowOriginsWrite )
154+ .asExpr ( )
155+ .( SliceLit )
156+ .getAnElement ( )
157+ .getStringValue ( )
158+ .toLowerCase ( ) = "null" and
113159 message =
114- headerAllowOrigin ( ) + " header is set to `" + allowOriginHW . getHeaderValue ( ) + "`, and " +
115- headerAllowCredentials ( ) + " is set to `true`"
160+ headerAllowOrigin ( ) + " header is set to `" + "null" + "`, and " + headerAllowCredentials ( ) +
161+ " is set to `true`"
116162}
117163
118164/**
@@ -170,15 +216,15 @@ module FromUntrustedFlow = TaintTracking::Global<FromUntrustedConfig>;
170216/**
171217 * Holds if the provided `allowOriginHW` is also destination of a `UntrustedFlowSource`.
172218 */
173- predicate flowsToGuardedByCheckOnUntrusted ( AllowOriginHeaderWrite allowOriginHW ) {
219+ predicate flowsToGuardedByCheckOnUntrusted ( DataFlow :: ExprNode allowOriginHW ) {
174220 exists ( DataFlow:: Node sink , ControlFlow:: ConditionGuardNode cgn |
175221 FromUntrustedFlow:: flowTo ( sink ) and FromUntrustedConfig:: isSinkCgn ( sink , cgn )
176222 |
177223 cgn .dominates ( allowOriginHW .getBasicBlock ( ) )
178224 )
179225}
180226
181- from AllowOriginHeaderWrite allowOriginHW , string message
227+ from DataFlow :: ExprNode allowOriginHW , string message
182228where
183229 allowCredentialsIsSetToTrue ( allowOriginHW ) and
184230 (
0 commit comments