@@ -705,6 +705,68 @@ module TaintTracking {
705
705
}
706
706
}
707
707
708
+ private module RegExpCaptureSteps {
709
+ /** Gets a reference to a string derived from the most recent RegExp match, such as `RegExp.$1` */
710
+ private DataFlow:: PropRead getAStaticCaptureRef ( ) {
711
+ result =
712
+ DataFlow:: globalVarRef ( "RegExp" )
713
+ .getAPropertyRead ( [ "$" + [ 1 .. 9 ] , "input" , "lastMatch" , "leftContext" , "rightContext" ,
714
+ "$&" , "$^" , "$`" ] )
715
+ }
716
+
717
+ /**
718
+ * Gets a control-flow node where `input` is used in a RegExp match.
719
+ */
720
+ private ControlFlowNode getACaptureSetter ( DataFlow:: Node input ) {
721
+ exists ( DataFlow:: MethodCallNode call | result = call .asExpr ( ) |
722
+ call .getMethodName ( ) = [ "search" , "replace" , "match" ] and input = call .getReceiver ( )
723
+ or
724
+ call .getMethodName ( ) = [ "test" , "exec" ] and input = call .getArgument ( 0 )
725
+ )
726
+ }
727
+
728
+ /**
729
+ * Gets a control-flow node that can locally reach the given static capture reference
730
+ * without passing through a capture setter.
731
+ *
732
+ * This is essentially an intraprocedural def-use analysis that ignores potential
733
+ * side effects from calls.
734
+ */
735
+ private ControlFlowNode getANodeReachingCaptureRef ( DataFlow:: PropRead read ) {
736
+ result = read .asExpr ( ) and
737
+ read = getAStaticCaptureRef ( )
738
+ or
739
+ exists ( ControlFlowNode mid |
740
+ mid = getANodeReachingCaptureRef ( read ) and
741
+ not mid = getACaptureSetter ( _) and
742
+ result = mid .getAPredecessor ( )
743
+ )
744
+ }
745
+
746
+ /**
747
+ * Holds if there is a step `pred -> succ` from the input of a RegExp match to
748
+ * a static property of `RegExp` defined.
749
+ */
750
+ private predicate staticRegExpCaptureStep ( DataFlow:: Node pred , DataFlow:: Node succ ) {
751
+ getACaptureSetter ( pred ) = getANodeReachingCaptureRef ( succ )
752
+ or
753
+ exists ( DataFlow:: MethodCallNode replace |
754
+ replace .getMethodName ( ) = "replace" and
755
+ getANodeReachingCaptureRef ( succ ) = replace .getCallback ( 1 ) .getFunction ( ) .getEntry ( ) and
756
+ pred = replace .getReceiver ( )
757
+ )
758
+ }
759
+
760
+ private class StaticRegExpCaptureStep extends AdditionalTaintStep {
761
+ StaticRegExpCaptureStep ( ) { staticRegExpCaptureStep ( this , _) }
762
+
763
+ override predicate step ( DataFlow:: Node pred , DataFlow:: Node succ ) {
764
+ pred = this and
765
+ staticRegExpCaptureStep ( this , succ )
766
+ }
767
+ }
768
+ }
769
+
708
770
/**
709
771
* A conditional checking a tainted string against a regular expression, which is
710
772
* considered to be a sanitizer for all configurations.
0 commit comments