14
14
import go
15
15
16
16
/**
17
- * A name of a type that will not be escaped when passed to
18
- * a `html/template` template.
17
+ * A type that will not be escaped when passed to a `html/template` template.
19
18
*/
20
- class PassthroughTypeName extends string {
21
- PassthroughTypeName ( ) { this = [ "HTML" , "HTMLAttr" , "JS" , "JSStr" , "CSS" , "Srcset" , "URL" ] }
19
+ class UnescapedType extends Type {
20
+ UnescapedType ( ) {
21
+ this .hasQualifiedName ( "html/template" ,
22
+ [ "CSS" , "HTML" , "HTMLAttr" , "JS" , "JSStr" , "Srcset" , "URL" ] )
23
+ }
22
24
}
23
25
24
26
/**
@@ -42,22 +44,22 @@ predicate isSinkToTemplateExec(DataFlow::Node sink, DataFlow::CallNode call) {
42
44
module UntrustedToTemplateExecWithConversionConfig implements DataFlow:: StateConfigSig {
43
45
private newtype TConversionState =
44
46
TUnconverted ( ) or
45
- TConverted ( PassthroughTypeName x )
47
+ TConverted ( UnescapedType unescapedType )
46
48
47
49
/**
48
50
* Flow state for tracking whether a conversion to a passthrough type has occurred.
49
51
*/
50
52
class FlowState extends TConversionState {
51
53
predicate isBeforeConversion ( ) { this instanceof TUnconverted }
52
54
53
- predicate isAfterConversion ( PassthroughTypeName x ) { this = TConverted ( x ) }
55
+ predicate isAfterConversion ( UnescapedType unescapedType ) { this = TConverted ( unescapedType ) }
54
56
55
57
/** Gets a textual representation of this element. */
56
58
string toString ( ) {
57
59
this .isBeforeConversion ( ) and result = "Unconverted"
58
60
or
59
- exists ( PassthroughTypeName x | this .isAfterConversion ( x ) |
60
- result = "Converted to template. " + x
61
+ exists ( UnescapedType unescapedType | this .isAfterConversion ( unescapedType ) |
62
+ result = "Converted to " + unescapedType . getQualifiedName ( )
61
63
)
62
64
}
63
65
}
@@ -82,13 +84,13 @@ module UntrustedToTemplateExecWithConversionConfig implements DataFlow::StateCon
82
84
predicate isAdditionalFlowStep (
83
85
DataFlow:: Node pred , FlowState predState , DataFlow:: Node succ , FlowState succState
84
86
) {
85
- exists ( ConversionExpr conversion , PassthroughTypeName name |
87
+ exists ( ConversionExpr conversion , UnescapedType unescapedType |
86
88
// If not yet converted, look for a conversion to a passthrough type
87
89
predState .isBeforeConversion ( ) and
88
- succState .isAfterConversion ( name ) and
90
+ succState .isAfterConversion ( unescapedType ) and
89
91
succ .( DataFlow:: TypeCastNode ) .getExpr ( ) = conversion and
90
92
pred .asExpr ( ) = conversion .getOperand ( ) and
91
- conversion .getType ( ) .getUnderlyingType * ( ) . hasQualifiedName ( "html/template" , name )
93
+ conversion .getType ( ) .getUnderlyingType * ( ) = unescapedType
92
94
)
93
95
}
94
96
}
@@ -100,11 +102,10 @@ import UntrustedToTemplateExecWithConversionFlow::PathGraph
100
102
101
103
from
102
104
UntrustedToTemplateExecWithConversionFlow:: PathNode untrustedSource ,
103
- UntrustedToTemplateExecWithConversionFlow:: PathNode templateExecCall ,
104
- PassthroughTypeName targetTypeName
105
+ UntrustedToTemplateExecWithConversionFlow:: PathNode templateExecCall , UnescapedType unescapedType
105
106
where
106
107
UntrustedToTemplateExecWithConversionFlow:: flowPath ( untrustedSource , templateExecCall ) and
107
- templateExecCall .getState ( ) .isAfterConversion ( targetTypeName )
108
+ templateExecCall .getState ( ) .isAfterConversion ( unescapedType )
108
109
select templateExecCall .getNode ( ) , untrustedSource , templateExecCall ,
109
- "Data from an $@ will not be auto-escaped because it was converted to template." + targetTypeName ,
110
- untrustedSource .getNode ( ) , "untrusted source"
110
+ "Data from an $@ will not be auto-escaped because it was converted to template." +
111
+ unescapedType . getName ( ) , untrustedSource .getNode ( ) , "untrusted source"
0 commit comments