@@ -319,8 +319,8 @@ module ReflectedXss {
319
319
send .getRouteHandler ( ) = h and
320
320
result = nonHtmlContentTypeHeader ( h )
321
321
|
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 )
324
324
)
325
325
}
326
326
@@ -333,40 +333,47 @@ module ReflectedXss {
333
333
}
334
334
335
335
/**
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`.
337
337
*/
338
- predicate isIrrelevantFor ( HTTP:: HeaderDefinition header , HTTP:: ResponseSendArgument sender ) {
338
+ predicate headerAffects ( HTTP:: HeaderDefinition header , HTTP:: ResponseSendArgument sender ) {
339
339
sender .getRouteHandler ( ) = header .getRouteHandler ( ) and
340
- not header .getBasicBlock ( ) .getASuccessor * ( ) = sender .getBasicBlock ( ) and
341
- not sender .getBasicBlock ( ) .getASuccessor * ( ) = header .getBasicBlock ( ) and
342
340
(
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 ( ) )
348
343
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 ( ) )
366
348
)
367
349
)
368
350
}
369
351
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
+
370
377
/**
371
378
* A regexp replacement involving an HTML meta-character, viewed as a sanitizer for
372
379
* XSS vulnerabilities.
0 commit comments