1111 */
1212
1313import go
14- import DataFlow:: PathGraph
1514
1615/**
1716 * Holds if the provided `untrusted` node flows into a conversion to a PassthroughType.
@@ -21,10 +20,10 @@ import DataFlow::PathGraph
2120predicate flowsFromUntrustedToConversion (
2221 DataFlow:: Node untrusted , PassthroughTypeName targetType , DataFlow:: Node conversionSink
2322) {
24- exists ( FlowConfFromUntrustedToPassthroughTypeConversion cfg , DataFlow:: Node source |
25- cfg . hasFlow ( source , conversionSink ) and
23+ exists ( DataFlow:: Node source |
24+ UntrustedToPassthroughTypeConversionFlow :: flow ( source , conversionSink ) and
2625 source = untrusted and
27- targetType = cfg . getDstTypeName ( )
26+ UntrustedToPassthroughTypeConversionConfig :: isSinkToPassthroughType ( conversionSink , targetType )
2827 )
2928}
3029
@@ -42,72 +41,45 @@ class PassthroughTypeName extends string {
4241 * this allows the injection of arbitrary content (html, css, js) into the generated
4342 * output of the templates.
4443 */
45- class FlowConfFromUntrustedToPassthroughTypeConversion extends TaintTracking :: Configuration {
46- PassthroughTypeName dstTypeName ;
44+ module UntrustedToPassthroughTypeConversionConfig implements DataFlow :: ConfigSig {
45+ predicate isSource ( DataFlow :: Node source ) { source instanceof UntrustedFlowSource }
4746
48- FlowConfFromUntrustedToPassthroughTypeConversion ( ) {
49- this = "UntrustedToConversion" + dstTypeName
50- }
51-
52- /**
53- * Gets the name of conversion's destination type.
54- */
55- PassthroughTypeName getDstTypeName ( ) { result = dstTypeName }
56-
57- override predicate isSource ( DataFlow:: Node source ) { source instanceof UntrustedFlowSource }
58-
59- private predicate isSinkToPassthroughType ( DataFlow:: TypeCastNode sink , PassthroughTypeName name ) {
47+ additional predicate isSinkToPassthroughType ( DataFlow:: TypeCastNode sink , PassthroughTypeName name ) {
6048 exists ( Type typ |
6149 typ = sink .getResultType ( ) and
6250 typ .getUnderlyingType * ( ) .hasQualifiedName ( "html/template" , name )
6351 )
6452 }
6553
66- override predicate isSink ( DataFlow:: Node sink ) { this . isSinkToPassthroughType ( sink , dstTypeName ) }
54+ predicate isSink ( DataFlow:: Node sink ) { isSinkToPassthroughType ( sink , _ ) }
6755
68- override predicate isSanitizer ( DataFlow:: Node sanitizer ) {
69- sanitizer instanceof SharedXss:: Sanitizer or sanitizer .getType ( ) instanceof NumericType
56+ predicate isBarrier ( DataFlow:: Node node ) {
57+ node instanceof SharedXss:: Sanitizer or node .getType ( ) instanceof NumericType
7058 }
7159}
7260
61+ module UntrustedToPassthroughTypeConversionFlow =
62+ TaintTracking:: Global< UntrustedToPassthroughTypeConversionConfig > ;
63+
7364/**
7465 * Holds if the provided `conversion` node flows into the provided `execSink`.
7566 */
7667predicate flowsFromConversionToExec (
7768 DataFlow:: Node conversion , PassthroughTypeName targetType , DataFlow:: Node execSink
7869) {
79- exists (
80- FlowConfPassthroughTypeConversionToTemplateExecutionCall cfg , DataFlow:: Node source ,
81- DataFlow:: Node execSinkLocal
82- |
83- cfg .hasFlow ( source , execSinkLocal ) and
84- source = conversion and
85- execSink = execSinkLocal and
86- targetType = cfg .getDstTypeName ( )
87- )
70+ PassthroughTypeConversionToTemplateExecutionCallFlow:: flow ( conversion , execSink ) and
71+ PassthroughTypeConversionToTemplateExecutionCallConfig:: isSourceConversionToPassthroughType ( conversion ,
72+ targetType )
8873}
8974
9075/**
9176 * A taint-tracking configuration for reasoning about when the result of a conversion
9277 * to a PassthroughType flows to a template execution call.
9378 */
94- class FlowConfPassthroughTypeConversionToTemplateExecutionCall extends TaintTracking:: Configuration {
95- PassthroughTypeName dstTypeName ;
96-
97- FlowConfPassthroughTypeConversionToTemplateExecutionCall ( ) {
98- this = "ConversionToExec" + dstTypeName
99- }
79+ module PassthroughTypeConversionToTemplateExecutionCallConfig implements DataFlow:: ConfigSig {
80+ predicate isSource ( DataFlow:: Node source ) { isSourceConversionToPassthroughType ( source , _) }
10081
101- /**
102- * Gets the name of conversion's destination type.
103- */
104- PassthroughTypeName getDstTypeName ( ) { result = dstTypeName }
105-
106- override predicate isSource ( DataFlow:: Node source ) {
107- this .isSourceConversionToPassthroughType ( source , dstTypeName )
108- }
109-
110- private predicate isSourceConversionToPassthroughType (
82+ additional predicate isSourceConversionToPassthroughType (
11183 DataFlow:: TypeCastNode source , PassthroughTypeName name
11284 ) {
11385 exists ( Type typ |
@@ -116,9 +88,12 @@ class FlowConfPassthroughTypeConversionToTemplateExecutionCall extends TaintTrac
11688 )
11789 }
11890
119- override predicate isSink ( DataFlow:: Node sink ) { isSinkToTemplateExec ( sink , _) }
91+ predicate isSink ( DataFlow:: Node sink ) { isSinkToTemplateExec ( sink , _) }
12092}
12193
94+ module PassthroughTypeConversionToTemplateExecutionCallFlow =
95+ TaintTracking:: Global< PassthroughTypeConversionToTemplateExecutionCallConfig > ;
96+
12297/**
12398 * Holds if the sink is a data value argument of a template execution call.
12499 */
@@ -137,37 +112,42 @@ predicate isSinkToTemplateExec(DataFlow::Node sink, DataFlow::CallNode call) {
137112 * A taint-tracking configuration for reasoning about when an UntrustedFlowSource
138113 * flows into a template executor call.
139114 */
140- class FlowConfFromUntrustedToTemplateExecutionCall extends TaintTracking:: Configuration {
141- FlowConfFromUntrustedToTemplateExecutionCall ( ) {
142- this = "FlowConfFromUntrustedToTemplateExecutionCall"
143- }
115+ module FromUntrustedToTemplateExecutionCallConfig implements DataFlow:: ConfigSig {
116+ predicate isSource ( DataFlow:: Node source ) { source instanceof UntrustedFlowSource }
144117
145- override predicate isSource ( DataFlow:: Node source ) { source instanceof UntrustedFlowSource }
146-
147- override predicate isSink ( DataFlow:: Node sink ) { isSinkToTemplateExec ( sink , _) }
118+ predicate isSink ( DataFlow:: Node sink ) { isSinkToTemplateExec ( sink , _) }
148119}
149120
121+ module FromUntrustedToTemplateExecutionCallFlow =
122+ TaintTracking:: Global< FromUntrustedToTemplateExecutionCallConfig > ;
123+
124+ import FromUntrustedToTemplateExecutionCallFlow:: PathGraph
125+
150126/**
151127 * Holds if the provided `untrusted` node flows into the provided `execSink`.
152128 */
153- predicate flowsFromUntrustedToExec ( DataFlow:: PathNode untrusted , DataFlow:: PathNode execSink ) {
154- exists ( FlowConfFromUntrustedToTemplateExecutionCall cfg | cfg .hasFlowPath ( untrusted , execSink ) )
129+ predicate flowsFromUntrustedToExec (
130+ FromUntrustedToTemplateExecutionCallFlow:: PathNode untrusted ,
131+ FromUntrustedToTemplateExecutionCallFlow:: PathNode execSink
132+ ) {
133+ FromUntrustedToTemplateExecutionCallFlow:: flowPath ( untrusted , execSink )
155134}
156135
157136from
158- DataFlow:: PathNode untrustedSource , DataFlow:: PathNode templateExecCall ,
159- PassthroughTypeName targetTypeName , DataFlow:: PathNode conversion
137+ FromUntrustedToTemplateExecutionCallFlow:: PathNode untrustedSource ,
138+ FromUntrustedToTemplateExecutionCallFlow:: PathNode templateExecCall ,
139+ PassthroughTypeName targetTypeName , DataFlow:: Node conversion
160140where
161141 // A = untrusted remote flow source
162142 // B = conversion to PassthroughType
163143 // C = template execution call
164144 // Flows:
165145 // A -> B
166- flowsFromUntrustedToConversion ( untrustedSource .getNode ( ) , targetTypeName , conversion . getNode ( ) ) and
146+ flowsFromUntrustedToConversion ( untrustedSource .getNode ( ) , targetTypeName , conversion ) and
167147 // B -> C
168- flowsFromConversionToExec ( conversion . getNode ( ) , targetTypeName , templateExecCall .getNode ( ) ) and
148+ flowsFromConversionToExec ( conversion , targetTypeName , templateExecCall .getNode ( ) ) and
169149 // A -> C
170150 flowsFromUntrustedToExec ( untrustedSource , templateExecCall )
171151select templateExecCall .getNode ( ) , untrustedSource , templateExecCall ,
172152 "Data from an $@ will not be auto-escaped because it was $@ to template." + targetTypeName ,
173- untrustedSource .getNode ( ) , "untrusted source" , conversion . getNode ( ) , "converted"
153+ untrustedSource .getNode ( ) , "untrusted source" , conversion , "converted"
0 commit comments