1414import go
1515
1616/**
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.
1918 */
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+ }
2224}
2325
2426/**
@@ -42,22 +44,22 @@ predicate isSinkToTemplateExec(DataFlow::Node sink, DataFlow::CallNode call) {
4244module UntrustedToTemplateExecWithConversionConfig implements DataFlow:: StateConfigSig {
4345 private newtype TConversionState =
4446 TUnconverted ( ) or
45- TConverted ( PassthroughTypeName x )
47+ TConverted ( UnescapedType unescapedType )
4648
4749 /**
4850 * Flow state for tracking whether a conversion to a passthrough type has occurred.
4951 */
5052 class FlowState extends TConversionState {
5153 predicate isBeforeConversion ( ) { this instanceof TUnconverted }
5254
53- predicate isAfterConversion ( PassthroughTypeName x ) { this = TConverted ( x ) }
55+ predicate isAfterConversion ( UnescapedType unescapedType ) { this = TConverted ( unescapedType ) }
5456
5557 /** Gets a textual representation of this element. */
5658 string toString ( ) {
5759 this .isBeforeConversion ( ) and result = "Unconverted"
5860 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 ( )
6163 )
6264 }
6365 }
@@ -82,13 +84,13 @@ module UntrustedToTemplateExecWithConversionConfig implements DataFlow::StateCon
8284 predicate isAdditionalFlowStep (
8385 DataFlow:: Node pred , FlowState predState , DataFlow:: Node succ , FlowState succState
8486 ) {
85- exists ( ConversionExpr conversion , PassthroughTypeName name |
87+ exists ( ConversionExpr conversion , UnescapedType unescapedType |
8688 // If not yet converted, look for a conversion to a passthrough type
8789 predState .isBeforeConversion ( ) and
88- succState .isAfterConversion ( name ) and
90+ succState .isAfterConversion ( unescapedType ) and
8991 succ .( DataFlow:: TypeCastNode ) .getExpr ( ) = conversion and
9092 pred .asExpr ( ) = conversion .getOperand ( ) and
91- conversion .getType ( ) .getUnderlyingType * ( ) . hasQualifiedName ( "html/template" , name )
93+ conversion .getType ( ) .getUnderlyingType * ( ) = unescapedType
9294 )
9395 }
9496}
@@ -100,11 +102,10 @@ import UntrustedToTemplateExecWithConversionFlow::PathGraph
100102
101103from
102104 UntrustedToTemplateExecWithConversionFlow:: PathNode untrustedSource ,
103- UntrustedToTemplateExecWithConversionFlow:: PathNode templateExecCall ,
104- PassthroughTypeName targetTypeName
105+ UntrustedToTemplateExecWithConversionFlow:: PathNode templateExecCall , UnescapedType unescapedType
105106where
106107 UntrustedToTemplateExecWithConversionFlow:: flowPath ( untrustedSource , templateExecCall ) and
107- templateExecCall .getState ( ) .isAfterConversion ( targetTypeName )
108+ templateExecCall .getState ( ) .isAfterConversion ( unescapedType )
108109select 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