diff --git a/ql/src/semmle/go/frameworks/Stdlib.qll b/ql/src/semmle/go/frameworks/Stdlib.qll index e46e98582c3..b43886d6307 100644 --- a/ql/src/semmle/go/frameworks/Stdlib.qll +++ b/ql/src/semmle/go/frameworks/Stdlib.qll @@ -28,6 +28,7 @@ import semmle.go.frameworks.stdlib.EncodingJson import semmle.go.frameworks.stdlib.EncodingPem import semmle.go.frameworks.stdlib.EncodingXml import semmle.go.frameworks.stdlib.Html +import semmle.go.frameworks.stdlib.HtmlTemplate import semmle.go.frameworks.stdlib.Path import semmle.go.frameworks.stdlib.PathFilepath import semmle.go.frameworks.stdlib.Reflect diff --git a/ql/src/semmle/go/frameworks/stdlib/HtmlTemplate.qll b/ql/src/semmle/go/frameworks/stdlib/HtmlTemplate.qll new file mode 100644 index 00000000000..c5bb6de1f14 --- /dev/null +++ b/ql/src/semmle/go/frameworks/stdlib/HtmlTemplate.qll @@ -0,0 +1,66 @@ +/** + * Provides classes modeling security-relevant aspects of the `html/template` package. + */ + +import go + +/** Provides models of commonly used functions in the `html/template` package. */ +module HtmlTemplate { + private class FunctionModels extends TaintTracking::FunctionModel { + FunctionInput inp; + FunctionOutput outp; + + FunctionModels() { + // signature: func HTMLEscape(w io.Writer, b []byte) + hasQualifiedName("html/template", "HTMLEscape") and + (inp.isParameter(1) and outp.isParameter(0)) + or + // signature: func HTMLEscapeString(s string) string + hasQualifiedName("html/template", "HTMLEscapeString") and + (inp.isParameter(0) and outp.isResult()) + or + // signature: func HTMLEscaper(args ...interface{}) string + hasQualifiedName("html/template", "HTMLEscaper") and + (inp.isParameter(_) and outp.isResult()) + or + // signature: func JSEscape(w io.Writer, b []byte) + hasQualifiedName("html/template", "JSEscape") and + (inp.isParameter(1) and outp.isParameter(0)) + or + // signature: func JSEscapeString(s string) string + hasQualifiedName("html/template", "JSEscapeString") and + (inp.isParameter(0) and outp.isResult()) + or + // signature: func JSEscaper(args ...interface{}) string + hasQualifiedName("html/template", "JSEscaper") and + (inp.isParameter(_) and outp.isResult()) + or + // signature: func URLQueryEscaper(args ...interface{}) string + hasQualifiedName("html/template", "URLQueryEscaper") and + (inp.isParameter(_) and outp.isResult()) + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + input = inp and output = outp + } + } + + private class MethodModels extends TaintTracking::FunctionModel, Method { + FunctionInput inp; + FunctionOutput outp; + + MethodModels() { + // signature: func (*Template).Execute(wr io.Writer, data interface{}) error + this.hasQualifiedName("html/template", "Template", "Execute") and + (inp.isParameter(1) and outp.isParameter(0)) + or + // signature: func (*Template).ExecuteTemplate(wr io.Writer, name string, data interface{}) error + this.hasQualifiedName("html/template", "Template", "ExecuteTemplate") and + (inp.isParameter(2) and outp.isParameter(0)) + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + input = inp and output = outp + } + } +} diff --git a/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/HtmlTemplate.go b/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/HtmlTemplate.go new file mode 100644 index 00000000000..5761afe247c --- /dev/null +++ b/ql/test/library-tests/semmle/go/frameworks/StdlibTaintFlow/HtmlTemplate.go @@ -0,0 +1,116 @@ +// Code generated by https://github.com/gagliardetto/codebox. DO NOT EDIT. + +package main + +import ( + "html/template" + "io" +) + +func TaintStepTest_HtmlTemplateHTMLEscape_B0I0O0(sourceCQL interface{}) interface{} { + fromByte656 := sourceCQL.([]byte) + var intoWriter414 io.Writer + template.HTMLEscape(intoWriter414, fromByte656) + return intoWriter414 +} + +func TaintStepTest_HtmlTemplateHTMLEscapeString_B0I0O0(sourceCQL interface{}) interface{} { + fromString518 := sourceCQL.(string) + intoString650 := template.HTMLEscapeString(fromString518) + return intoString650 +} + +func TaintStepTest_HtmlTemplateHTMLEscaper_B0I0O0(sourceCQL interface{}) interface{} { + fromInterface784 := sourceCQL.(interface{}) + intoString957 := template.HTMLEscaper(fromInterface784) + return intoString957 +} + +func TaintStepTest_HtmlTemplateJSEscape_B0I0O0(sourceCQL interface{}) interface{} { + fromByte520 := sourceCQL.([]byte) + var intoWriter443 io.Writer + template.JSEscape(intoWriter443, fromByte520) + return intoWriter443 +} + +func TaintStepTest_HtmlTemplateJSEscapeString_B0I0O0(sourceCQL interface{}) interface{} { + fromString127 := sourceCQL.(string) + intoString483 := template.JSEscapeString(fromString127) + return intoString483 +} + +func TaintStepTest_HtmlTemplateJSEscaper_B0I0O0(sourceCQL interface{}) interface{} { + fromInterface989 := sourceCQL.(interface{}) + intoString982 := template.JSEscaper(fromInterface989) + return intoString982 +} + +func TaintStepTest_HtmlTemplateURLQueryEscaper_B0I0O0(sourceCQL interface{}) interface{} { + fromInterface417 := sourceCQL.(interface{}) + intoString584 := template.URLQueryEscaper(fromInterface417) + return intoString584 +} + +func TaintStepTest_HtmlTemplateTemplateExecute_B0I0O0(sourceCQL interface{}) interface{} { + fromInterface991 := sourceCQL.(interface{}) + var intoWriter881 io.Writer + var mediumObjCQL template.Template + mediumObjCQL.Execute(intoWriter881, fromInterface991) + return intoWriter881 +} + +func TaintStepTest_HtmlTemplateTemplateExecuteTemplate_B0I0O0(sourceCQL interface{}) interface{} { + fromInterface186 := sourceCQL.(interface{}) + var intoWriter284 io.Writer + var mediumObjCQL template.Template + mediumObjCQL.ExecuteTemplate(intoWriter284, "", fromInterface186) + return intoWriter284 +} + +func RunAllTaints_HtmlTemplate() { + { + source := newSource(0) + out := TaintStepTest_HtmlTemplateHTMLEscape_B0I0O0(source) + sink(0, out) + } + { + source := newSource(1) + out := TaintStepTest_HtmlTemplateHTMLEscapeString_B0I0O0(source) + sink(1, out) + } + { + source := newSource(2) + out := TaintStepTest_HtmlTemplateHTMLEscaper_B0I0O0(source) + sink(2, out) + } + { + source := newSource(3) + out := TaintStepTest_HtmlTemplateJSEscape_B0I0O0(source) + sink(3, out) + } + { + source := newSource(4) + out := TaintStepTest_HtmlTemplateJSEscapeString_B0I0O0(source) + sink(4, out) + } + { + source := newSource(5) + out := TaintStepTest_HtmlTemplateJSEscaper_B0I0O0(source) + sink(5, out) + } + { + source := newSource(6) + out := TaintStepTest_HtmlTemplateURLQueryEscaper_B0I0O0(source) + sink(6, out) + } + { + source := newSource(7) + out := TaintStepTest_HtmlTemplateTemplateExecute_B0I0O0(source) + sink(7, out) + } + { + source := newSource(8) + out := TaintStepTest_HtmlTemplateTemplateExecuteTemplate_B0I0O0(source) + sink(8, out) + } +}