@@ -319,8 +319,8 @@ module ReflectedXss {
319319 send .getRouteHandler ( ) = h and
320320 result = nonHtmlContentTypeHeader ( h )
321321 |
322- // The HeaderDefinition affects a response sent at `send`.
323- not isIrrelevantFor ( result , send )
322+ // The HeaderDefinition affects a response sent at `send`.
323+ headerAffects ( result , send )
324324 )
325325 }
326326
@@ -333,40 +333,47 @@ module ReflectedXss {
333333 }
334334
335335 /**
336- * Holds if a header set in `header` is unlikely to affect a response sent at `sender`.
336+ * Holds if a header set in `header` is likely to affect a response sent at `sender`.
337337 */
338- predicate isIrrelevantFor ( HTTP:: HeaderDefinition header , HTTP:: ResponseSendArgument sender ) {
338+ predicate headerAffects ( HTTP:: HeaderDefinition header , HTTP:: ResponseSendArgument sender ) {
339339 sender .getRouteHandler ( ) = header .getRouteHandler ( ) and
340- not header .getBasicBlock ( ) .getASuccessor * ( ) = sender .getBasicBlock ( ) and
341- not sender .getBasicBlock ( ) .getASuccessor * ( ) = header .getBasicBlock ( ) and
342340 (
343- // If there is another header `otherHeader` next to `sender`, then `header` is probably irrelevant.
344- exists ( HTTP:: HeaderDefinition otherHeader | not header = otherHeader |
345- otherHeader .getBasicBlock ( ) .getASuccessor * ( ) = sender .getBasicBlock ( ) and
346- not otherHeader = nonHtmlContentTypeHeader ( sender .getRouteHandler ( ) )
347- )
341+ // `sender` is affected by a dominating `header`.
342+ header .getBasicBlock ( ) .( ReachableBasicBlock ) .dominates ( sender .getBasicBlock ( ) )
348343 or
349- // Tries to recognize variants of:
350- // ```
351- // response.writeHead(500, {'Content-Type': 'text/plain'});
352- // response.end('Some error');
353- // return;
354- // ```
355- exists ( ReachableBasicBlock headerBlock | headerBlock = header .getBasicBlock ( ) |
356- headerBlock .getASuccessor ( ) instanceof ControlFlowExitNode and
357- strictcount ( headerBlock .getASuccessor ( ) ) = 1 and
358- not (
359- exists ( DataFlow:: CallNode call |
360- exists ( call .getACallee ( ) ) and
361- call .getBasicBlock ( ) = headerBlock
362- )
363- or
364- exists ( Expr e | e .getBasicBlock ( ) = headerBlock and e instanceof Function )
365- )
344+ // There is no dominating header, and `header` is non-local.
345+ not isLocalHeaderDefinition ( header ) and
346+ not exists ( HTTP:: HeaderDefinition dominatingHeader |
347+ dominatingHeader .getBasicBlock ( ) .( ReachableBasicBlock ) .dominates ( sender .getBasicBlock ( ) )
366348 )
367349 )
368350 }
369351
352+ /**
353+ * Holds if the HeaderDefinition `header` seems to be local.
354+ * A HeaderDefinition is local if it dominates exactly one `ResponseSendArgument`.
355+ *
356+ * Recognizes variants of:
357+ * ```
358+ * response.writeHead(500, ...);
359+ * response.end('Some error');
360+ * return;
361+ * ```
362+ */
363+ predicate isLocalHeaderDefinition ( HTTP:: HeaderDefinition header ) {
364+ exists ( ReachableBasicBlock headerBlock |
365+ headerBlock = header .getBasicBlock ( ) .( ReachableBasicBlock )
366+ |
367+ 1 =
368+ strictcount ( HTTP:: ResponseSendArgument sender |
369+ sender .getRouteHandler ( ) = header .getRouteHandler ( ) and
370+ header .getBasicBlock ( ) .( ReachableBasicBlock ) .dominates ( sender .getBasicBlock ( ) )
371+ ) and
372+ // doesn't dominate something that looks like a callback.
373+ not exists ( Expr e | e instanceof Function | headerBlock .dominates ( e .getBasicBlock ( ) ) )
374+ )
375+ }
376+
370377 /**
371378 * A regexp replacement involving an HTML meta-character, viewed as a sanitizer for
372379 * XSS vulnerabilities.
0 commit comments