diff --git a/change-notes/2020-12-08-beego.md b/change-notes/2020-12-08-beego.md new file mode 100644 index 00000000000..59084d625e8 --- /dev/null +++ b/change-notes/2020-12-08-beego.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* Added support for the Beego web framework diff --git a/ql/src/go.qll b/ql/src/go.qll index 47126d338c5..9ce96a425a1 100644 --- a/ql/src/go.qll +++ b/ql/src/go.qll @@ -29,6 +29,7 @@ import semmle.go.dataflow.GlobalValueNumbering import semmle.go.dataflow.SSA import semmle.go.dataflow.TaintTracking import semmle.go.dataflow.TaintTracking2 +import semmle.go.frameworks.Beego import semmle.go.frameworks.Chi import semmle.go.frameworks.Echo import semmle.go.frameworks.Email diff --git a/ql/src/semmle/go/concepts/HTTP.qll b/ql/src/semmle/go/concepts/HTTP.qll index 6f0547027a8..b4622b09515 100644 --- a/ql/src/semmle/go/concepts/HTTP.qll +++ b/ql/src/semmle/go/concepts/HTTP.qll @@ -66,11 +66,17 @@ module HTTP { /** Holds if this header write defines the header `header`. */ predicate definesHeader(string header, string value) { - header = this.getName().getStringValue().toLowerCase() and + header = this.getHeaderName() and value = this.getValue().getStringValue() } - /** Gets the node representing the name of the header defined by this write. */ + /** + * Gets the node representing the name of the header defined by this write. + * + * Note that a `HeaderWrite` targeting a constant header (e.g. a routine that always + * sets the `Content-Type` header) may not have such a node, so callers should use + * `getHeaderName` in preference to this method). + */ abstract DataFlow::Node getName(); /** Gets the node representing the value of the header defined by this write. */ @@ -98,7 +104,13 @@ module HTTP { /** Holds if this header write defines the header `header`. */ predicate definesHeader(string header, string value) { self.definesHeader(header, value) } - /** Gets the node representing the name of the header defined by this write. */ + /** + * Gets the node representing the name of the header defined by this write. + * + * Note that a `HeaderWrite` targeting a constant header (e.g. a routine that always + * sets the `Content-Type` header) may not have such a node, so callers should use + * `getHeaderName` in preference to this method). + */ DataFlow::Node getName() { result = self.getName() } /** Gets the node representing the value of the header defined by this write. */ @@ -173,7 +185,7 @@ module HTTP { /** Gets a dataflow node for a content-type associated with this body. */ DataFlow::Node getAContentTypeNode() { exists(HTTP::HeaderWrite hw | hw = getResponseWriter().getAHeaderWrite() | - hw.getName().getStringValue().toLowerCase() = "content-type" and + hw.getHeaderName() = "content-type" and result = hw.getValue() ) } diff --git a/ql/src/semmle/go/dataflow/FunctionInputsAndOutputs.qll b/ql/src/semmle/go/dataflow/FunctionInputsAndOutputs.qll index 7e884513066..e3d3059cfbc 100644 --- a/ql/src/semmle/go/dataflow/FunctionInputsAndOutputs.qll +++ b/ql/src/semmle/go/dataflow/FunctionInputsAndOutputs.qll @@ -62,7 +62,7 @@ module FunctionInput { FunctionInput functionResult() { result.isResult() } /** Gets a `FunctionInput` representing the `i`th result. */ - FunctionInput functionResult(int i) { result.isParameter(i) } + FunctionInput functionResult(int i) { result.isResult(i) } } /** A parameter position of a function, viewed as a source of input. */ @@ -196,7 +196,7 @@ module FunctionOutput { FunctionOutput functionResult() { result.isResult() } /** Gets a `FunctionOutput` representing the `i`th result. */ - FunctionOutput functionResult(int i) { result.isParameter(i) } + FunctionOutput functionResult(int i) { result.isResult(i) } /** Gets a `FunctionOutput` representing the receiver after a function returns. */ FunctionOutput receiver() { result.isReceiver() } diff --git a/ql/src/semmle/go/frameworks/Beego.qll b/ql/src/semmle/go/frameworks/Beego.qll new file mode 100644 index 00000000000..6581f0b462c --- /dev/null +++ b/ql/src/semmle/go/frameworks/Beego.qll @@ -0,0 +1,356 @@ +/** + * Provides classes for working with untrusted flow sources, sinks and taint propagators + * from the `github.com/astaxie/beego` package. + */ + +import go +import semmle.go.security.Xss +private import semmle.go.security.SafeUrlFlowCustomizations + +module Beego { + /** Gets the package name. */ + bindingset[result] + string packagePath() { result = package("github.com/astaxie/beego", "") } + + /** Gets the context subpackage name. */ + bindingset[result] + string contextPackagePath() { result = package("github.com/astaxie/beego", "context") } + + /** Gets the logs subpackage name. */ + bindingset[result] + string logsPackagePath() { result = package("github.com/astaxie/beego", "logs") } + + /** Gets the utils subpackage name. */ + bindingset[result] + string utilsPackagePath() { result = package("github.com/astaxie/beego", "utils") } + + /** + * `BeegoInput` sources of untrusted data. + */ + private class BeegoInputSource extends UntrustedFlowSource::Range { + string methodName; + FunctionOutput output; + + BeegoInputSource() { + exists(DataFlow::MethodCallNode c | this = output.getExitNode(c) | + c.getTarget().hasQualifiedName(contextPackagePath(), "BeegoInput", methodName) + ) and + ( + methodName = "Bind" and + output.isParameter(0) + or + methodName in [ + "Cookie", "Data", "GetData", "Header", "Param", "Params", "Query", "Refer", "Referer", + "URI", "URL", "UserAgent" + ] and + output.isResult(0) + ) + } + + predicate isSafeUrlSource() { methodName in ["URI", "URL"] } + } + + /** `BeegoInput` sources that are safe to use for redirection. */ + private class BeegoInputSafeUrlSource extends SafeUrlFlow::Source { + BeegoInputSafeUrlSource() { this.(BeegoInputSource).isSafeUrlSource() } + } + + /** + * `beego.Controller` sources of untrusted data. + */ + private class BeegoControllerSource extends UntrustedFlowSource::Range { + string methodName; + FunctionOutput output; + + BeegoControllerSource() { + exists(DataFlow::MethodCallNode c | + c.getTarget().hasQualifiedName(packagePath(), "Controller", methodName) + | + this = output.getExitNode(c) + ) and + ( + methodName = "ParseForm" and + output.isParameter(0) + or + methodName in ["GetFile", "GetFiles", "GetString", "GetStrings", "Input"] and + output.isResult(0) + or + methodName = "GetFile" and + output.isResult(1) + ) + } + } + + /** + * `beego/context.Context` sources of untrusted data. + */ + private class BeegoContextSource extends UntrustedFlowSource::Range { + BeegoContextSource() { + exists(Method m | m.hasQualifiedName(contextPackagePath(), "Context", "GetCookie") | + this = m.getACall().getResult() + ) + } + } + + private class BeegoOutputInstance extends HTTP::ResponseWriter::Range { + SsaWithFields v; + + BeegoOutputInstance() { + this = v.getBaseVariable().getSourceVariable() and + v.getType().(PointerType).getBaseType().hasQualifiedName(contextPackagePath(), "BeegoOutput") + } + + override DataFlow::Node getANode() { result = v.similar().getAUse().getASuccessor*() } + + /** Gets a header object that corresponds to this HTTP response. */ + DataFlow::MethodCallNode getAHeaderObject() { + result.getTarget().getName() = ["ContentType", "Header"] and + this.getANode() = result.getReceiver() + } + } + + private class BeegoHeaderWrite extends HTTP::HeaderWrite::Range, DataFlow::MethodCallNode { + string methodName; + + BeegoHeaderWrite() { + this.getTarget().hasQualifiedName(contextPackagePath(), "BeegoOutput", methodName) and + methodName in ["ContentType", "Header"] + } + + override DataFlow::Node getName() { methodName = "Header" and result = this.getArgument(0) } + + override string getHeaderName() { + result = HTTP::HeaderWrite::Range.super.getHeaderName() + or + methodName = "ContentType" and result = "content-type" + } + + override DataFlow::Node getValue() { + if methodName = "ContentType" + then result = this.getArgument(0) + else result = this.getArgument(1) + } + + override HTTP::ResponseWriter getResponseWriter() { + result.(BeegoOutputInstance).getAHeaderObject() = this + } + } + + private class BeegoResponseBody extends HTTP::ResponseBody::Range { + DataFlow::MethodCallNode call; + string methodName; + + BeegoResponseBody() { + exists(Method m | m.hasQualifiedName(contextPackagePath(), "BeegoOutput", methodName) | + call = m.getACall() and + this = call.getArgument(0) + ) and + methodName in ["Body", "JSON", "JSONP", "ServeFormatted", "XML", "YAML"] + } + + override HTTP::ResponseWriter getResponseWriter() { result.getANode() = call.getReceiver() } + + override string getAContentType() { + // Super-method provides content-types for `Body`, which requires us to search + // for `ContentType` and `Header` calls against the same `BeegoOutput` instance + result = super.getAContentType() + or + // Specifically describe methods that set the content-type and body in one operation: + result = "application/json" and methodName = "JSON" + or + result = "application/javascript" and methodName = "JSONP" + or + // Actually ServeFormatted can serve JSON, XML or YAML depending on the incoming + // `Accept` header, but the important bit is this method cannot serve text/html. + result = "application/json" and methodName = "ServeFormatted" + or + result = "text/xml" and methodName = "XML" + or + result = "application/x-yaml" and methodName = "YAML" + } + } + + private class ControllerResponseBody extends HTTP::ResponseBody::Range { + string name; + + ControllerResponseBody() { + exists(Method m | m.hasQualifiedName(packagePath(), "Controller", name) | + name = "CustomAbort" and this = m.getACall().getArgument(1) + or + name = "SetData" and this = m.getACall().getArgument(0) + ) + } + + override HTTP::ResponseWriter getResponseWriter() { none() } + + override string getAContentType() { + // Actually SetData can serve JSON, XML or YAML depending on the incoming + // `Accept` header, but the important bit is this method cannot serve text/html. + result = "application/json" and name = "SetData" + // CustomAbort doesn't specify a content type, so we assume anything could happen. + } + } + + private class ContextResponseBody extends HTTP::ResponseBody::Range { + string name; + + ContextResponseBody() { + exists(Method m | m.hasQualifiedName(contextPackagePath(), "Context", name) | + name = "Abort" and this = m.getACall().getArgument(1) + or + name = "WriteString" and this = m.getACall().getArgument(0) + ) + } + + override HTTP::ResponseWriter getResponseWriter() { none() } + + // Neither method is likely to be used with well-typed data such as JSON output, + // because there are better methods to do this. Assume the Content-Type could + // be anything. + override string getAContentType() { none() } + } + + private string getALogFunctionName() { + result = + [ + "Alert", "Critical", "Debug", "Emergency", "Error", "Info", "Informational", "Notice", + "Trace", "Warn", "Warning" + ] + } + + private class ToplevelBeegoLoggers extends LoggerCall::Range, DataFlow::CallNode { + ToplevelBeegoLoggers() { + this.getTarget().hasQualifiedName([packagePath(), logsPackagePath()], getALogFunctionName()) + } + + override DataFlow::Node getAMessageComponent() { result = this.getAnArgument() } + } + + private class BeegoLoggerMethods extends LoggerCall::Range, DataFlow::MethodCallNode { + BeegoLoggerMethods() { + this.getTarget().hasQualifiedName(logsPackagePath(), "BeeLogger", getALogFunctionName()) + } + + override DataFlow::Node getAMessageComponent() { result = this.getAnArgument() } + } + + private class UtilLoggers extends LoggerCall::Range, DataFlow::CallNode { + UtilLoggers() { this.getTarget().hasQualifiedName(utilsPackagePath(), "Display") } + + override DataFlow::Node getAMessageComponent() { result = this.getAnArgument() } + } + + private class TopLevelTaintPropagators extends TaintTracking::FunctionModel { + string name; + + TopLevelTaintPropagators() { + this.hasQualifiedName(packagePath(), name) and + name in ["HTML2str", "Htmlquote", "Htmlunquote", "MapGet", "ParseForm", "Str2html", "Substr"] + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + name in ["HTML2str", "Htmlquote", "Htmlunquote", "MapGet", "Str2html", "Substr"] and + input.isParameter(0) and + output.isResult(0) + or + name = "ParseForm" and + input.isParameter(0) and + output.isParameter(1) + } + } + + private class ContextTaintPropagators extends TaintTracking::FunctionModel { + ContextTaintPropagators() { this.hasQualifiedName(contextPackagePath(), "WriteBody") } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + input.isParameter(2) and output.isParameter(1) + } + } + + private class HtmlQuoteSanitizer extends SharedXss::Sanitizer { + HtmlQuoteSanitizer() { + exists(DataFlow::CallNode c | c.getTarget().hasQualifiedName(packagePath(), "Htmlquote") | + this = c.getArgument(0) + ) + } + } + + private class FsOperations extends FileSystemAccess::Range, DataFlow::CallNode { + FsOperations() { + this.getTarget().hasQualifiedName(packagePath(), "Walk") + or + exists(Method m | this = m.getACall() | + m.hasQualifiedName(packagePath(), "FileSystem", "Open") or + m.hasQualifiedName(packagePath(), "Controller", "SaveToFile") + ) + } + + override DataFlow::Node getAPathArgument() { + this.getTarget().getName() = ["Walk", "SaveToFile"] and result = this.getArgument(1) + or + this.getTarget().getName() = "Open" and result = this.getArgument(0) + } + } + + private class RedirectMethods extends HTTP::Redirect::Range, DataFlow::CallNode { + string package; + string className; + + RedirectMethods() { + ( + package = packagePath() and className = "Controller" + or + package = contextPackagePath() and className = "Context" + ) and + this = any(Method m | m.hasQualifiedName(package, className, "Redirect")).getACall() + } + + override DataFlow::Node getUrl() { + className = "Controller" and result = this.getArgument(0) + or + className = "Context" and result = this.getArgument(1) + } + + override HTTP::ResponseWriter getResponseWriter() { none() } + } + + private class UtilsTaintPropagators extends TaintTracking::FunctionModel { + string name; + + UtilsTaintPropagators() { + this.hasQualifiedName(utilsPackagePath(), name) and + name in [ + "GetDisplayString", "SliceChunk", "SliceDiff", "SliceFilter", "SliceIntersect", + "SliceMerge", "SlicePad", "SliceRand", "SliceReduce", "SliceShuffle", "SliceUnique" + ] + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + name in [ + "GetDisplayString", "SliceIntersect", "SliceMerge", "SlicePad", "SliceRand", + "SliceShuffle", "SliceUnique" + ] and + input.isParameter(_) and + output.isResult(0) + or + name in ["SliceChunk", "SliceDiff", "SliceFilter", "SliceReduce"] and + input.isParameter(0) and + output.isResult(0) + } + } + + private class BeeMapModels extends TaintTracking::FunctionModel, Method { + string name; + + BeeMapModels() { + this.hasQualifiedName(utilsPackagePath(), "BeeMap", name) and + name in ["Get", "Set", "Items"] + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + name = "Set" and input.isParameter(1) and output.isReceiver() + or + name in ["Get", "Items"] and input.isReceiver() and output.isResult(0) + } + } +} diff --git a/ql/test/library-tests/semmle/go/frameworks/Beego/CleartextLogging.expected b/ql/test/library-tests/semmle/go/frameworks/Beego/CleartextLogging.expected new file mode 100644 index 00000000000..2d570925145 --- /dev/null +++ b/ql/test/library-tests/semmle/go/frameworks/Beego/CleartextLogging.expected @@ -0,0 +1,71 @@ +edges +nodes +| test.go:147:14:147:21 | password | semmle.label | password | +| test.go:148:17:148:24 | password | semmle.label | password | +| test.go:149:14:149:21 | password | semmle.label | password | +| test.go:150:18:150:25 | password | semmle.label | password | +| test.go:151:14:151:21 | password | semmle.label | password | +| test.go:152:13:152:20 | password | semmle.label | password | +| test.go:153:22:153:29 | password | semmle.label | password | +| test.go:154:15:154:22 | password | semmle.label | password | +| test.go:155:14:155:21 | password | semmle.label | password | +| test.go:156:13:156:20 | password | semmle.label | password | +| test.go:157:16:157:23 | password | semmle.label | password | +| test.go:158:13:158:20 | password | semmle.label | password | +| test.go:159:16:159:23 | password | semmle.label | password | +| test.go:160:13:160:20 | password | semmle.label | password | +| test.go:161:17:161:24 | password | semmle.label | password | +| test.go:162:13:162:20 | password | semmle.label | password | +| test.go:163:12:163:19 | password | semmle.label | password | +| test.go:164:21:164:28 | password | semmle.label | password | +| test.go:165:14:165:21 | password | semmle.label | password | +| test.go:166:13:166:20 | password | semmle.label | password | +| test.go:167:12:167:19 | password | semmle.label | password | +| test.go:168:15:168:22 | password | semmle.label | password | +| test.go:169:15:169:22 | password | semmle.label | password | +| test.go:170:18:170:25 | password | semmle.label | password | +| test.go:171:15:171:22 | password | semmle.label | password | +| test.go:172:19:172:26 | password | semmle.label | password | +| test.go:173:15:173:22 | password | semmle.label | password | +| test.go:174:14:174:21 | password | semmle.label | password | +| test.go:175:23:175:30 | password | semmle.label | password | +| test.go:176:16:176:23 | password | semmle.label | password | +| test.go:177:15:177:22 | password | semmle.label | password | +| test.go:178:14:178:21 | password | semmle.label | password | +| test.go:179:17:179:24 | password | semmle.label | password | +| test.go:180:16:180:23 | password | semmle.label | password | +#select +| test.go:147:14:147:21 | password | test.go:147:14:147:21 | password | test.go:147:14:147:21 | password | Sensitive data returned by $@ is logged here. | test.go:147:14:147:21 | password | an access to password | +| test.go:148:17:148:24 | password | test.go:148:17:148:24 | password | test.go:148:17:148:24 | password | Sensitive data returned by $@ is logged here. | test.go:148:17:148:24 | password | an access to password | +| test.go:149:14:149:21 | password | test.go:149:14:149:21 | password | test.go:149:14:149:21 | password | Sensitive data returned by $@ is logged here. | test.go:149:14:149:21 | password | an access to password | +| test.go:150:18:150:25 | password | test.go:150:18:150:25 | password | test.go:150:18:150:25 | password | Sensitive data returned by $@ is logged here. | test.go:150:18:150:25 | password | an access to password | +| test.go:151:14:151:21 | password | test.go:151:14:151:21 | password | test.go:151:14:151:21 | password | Sensitive data returned by $@ is logged here. | test.go:151:14:151:21 | password | an access to password | +| test.go:152:13:152:20 | password | test.go:152:13:152:20 | password | test.go:152:13:152:20 | password | Sensitive data returned by $@ is logged here. | test.go:152:13:152:20 | password | an access to password | +| test.go:153:22:153:29 | password | test.go:153:22:153:29 | password | test.go:153:22:153:29 | password | Sensitive data returned by $@ is logged here. | test.go:153:22:153:29 | password | an access to password | +| test.go:154:15:154:22 | password | test.go:154:15:154:22 | password | test.go:154:15:154:22 | password | Sensitive data returned by $@ is logged here. | test.go:154:15:154:22 | password | an access to password | +| test.go:155:14:155:21 | password | test.go:155:14:155:21 | password | test.go:155:14:155:21 | password | Sensitive data returned by $@ is logged here. | test.go:155:14:155:21 | password | an access to password | +| test.go:156:13:156:20 | password | test.go:156:13:156:20 | password | test.go:156:13:156:20 | password | Sensitive data returned by $@ is logged here. | test.go:156:13:156:20 | password | an access to password | +| test.go:157:16:157:23 | password | test.go:157:16:157:23 | password | test.go:157:16:157:23 | password | Sensitive data returned by $@ is logged here. | test.go:157:16:157:23 | password | an access to password | +| test.go:158:13:158:20 | password | test.go:158:13:158:20 | password | test.go:158:13:158:20 | password | Sensitive data returned by $@ is logged here. | test.go:158:13:158:20 | password | an access to password | +| test.go:159:16:159:23 | password | test.go:159:16:159:23 | password | test.go:159:16:159:23 | password | Sensitive data returned by $@ is logged here. | test.go:159:16:159:23 | password | an access to password | +| test.go:160:13:160:20 | password | test.go:160:13:160:20 | password | test.go:160:13:160:20 | password | Sensitive data returned by $@ is logged here. | test.go:160:13:160:20 | password | an access to password | +| test.go:161:17:161:24 | password | test.go:161:17:161:24 | password | test.go:161:17:161:24 | password | Sensitive data returned by $@ is logged here. | test.go:161:17:161:24 | password | an access to password | +| test.go:162:13:162:20 | password | test.go:162:13:162:20 | password | test.go:162:13:162:20 | password | Sensitive data returned by $@ is logged here. | test.go:162:13:162:20 | password | an access to password | +| test.go:163:12:163:19 | password | test.go:163:12:163:19 | password | test.go:163:12:163:19 | password | Sensitive data returned by $@ is logged here. | test.go:163:12:163:19 | password | an access to password | +| test.go:164:21:164:28 | password | test.go:164:21:164:28 | password | test.go:164:21:164:28 | password | Sensitive data returned by $@ is logged here. | test.go:164:21:164:28 | password | an access to password | +| test.go:165:14:165:21 | password | test.go:165:14:165:21 | password | test.go:165:14:165:21 | password | Sensitive data returned by $@ is logged here. | test.go:165:14:165:21 | password | an access to password | +| test.go:166:13:166:20 | password | test.go:166:13:166:20 | password | test.go:166:13:166:20 | password | Sensitive data returned by $@ is logged here. | test.go:166:13:166:20 | password | an access to password | +| test.go:167:12:167:19 | password | test.go:167:12:167:19 | password | test.go:167:12:167:19 | password | Sensitive data returned by $@ is logged here. | test.go:167:12:167:19 | password | an access to password | +| test.go:168:15:168:22 | password | test.go:168:15:168:22 | password | test.go:168:15:168:22 | password | Sensitive data returned by $@ is logged here. | test.go:168:15:168:22 | password | an access to password | +| test.go:169:15:169:22 | password | test.go:169:15:169:22 | password | test.go:169:15:169:22 | password | Sensitive data returned by $@ is logged here. | test.go:169:15:169:22 | password | an access to password | +| test.go:170:18:170:25 | password | test.go:170:18:170:25 | password | test.go:170:18:170:25 | password | Sensitive data returned by $@ is logged here. | test.go:170:18:170:25 | password | an access to password | +| test.go:171:15:171:22 | password | test.go:171:15:171:22 | password | test.go:171:15:171:22 | password | Sensitive data returned by $@ is logged here. | test.go:171:15:171:22 | password | an access to password | +| test.go:172:19:172:26 | password | test.go:172:19:172:26 | password | test.go:172:19:172:26 | password | Sensitive data returned by $@ is logged here. | test.go:172:19:172:26 | password | an access to password | +| test.go:173:15:173:22 | password | test.go:173:15:173:22 | password | test.go:173:15:173:22 | password | Sensitive data returned by $@ is logged here. | test.go:173:15:173:22 | password | an access to password | +| test.go:174:14:174:21 | password | test.go:174:14:174:21 | password | test.go:174:14:174:21 | password | Sensitive data returned by $@ is logged here. | test.go:174:14:174:21 | password | an access to password | +| test.go:175:23:175:30 | password | test.go:175:23:175:30 | password | test.go:175:23:175:30 | password | Sensitive data returned by $@ is logged here. | test.go:175:23:175:30 | password | an access to password | +| test.go:176:16:176:23 | password | test.go:176:16:176:23 | password | test.go:176:16:176:23 | password | Sensitive data returned by $@ is logged here. | test.go:176:16:176:23 | password | an access to password | +| test.go:177:15:177:22 | password | test.go:177:15:177:22 | password | test.go:177:15:177:22 | password | Sensitive data returned by $@ is logged here. | test.go:177:15:177:22 | password | an access to password | +| test.go:178:14:178:21 | password | test.go:178:14:178:21 | password | test.go:178:14:178:21 | password | Sensitive data returned by $@ is logged here. | test.go:178:14:178:21 | password | an access to password | +| test.go:179:17:179:24 | password | test.go:179:17:179:24 | password | test.go:179:17:179:24 | password | Sensitive data returned by $@ is logged here. | test.go:179:17:179:24 | password | an access to password | +| test.go:180:16:180:23 | password | test.go:180:16:180:23 | password | test.go:180:16:180:23 | password | Sensitive data returned by $@ is logged here. | test.go:180:16:180:23 | password | an access to password | diff --git a/ql/test/library-tests/semmle/go/frameworks/Beego/CleartextLogging.qlref b/ql/test/library-tests/semmle/go/frameworks/Beego/CleartextLogging.qlref new file mode 100644 index 00000000000..21eebbd09be --- /dev/null +++ b/ql/test/library-tests/semmle/go/frameworks/Beego/CleartextLogging.qlref @@ -0,0 +1 @@ +Security/CWE-312/CleartextLogging.ql diff --git a/ql/test/library-tests/semmle/go/frameworks/Beego/OpenRedirect.expected b/ql/test/library-tests/semmle/go/frameworks/Beego/OpenRedirect.expected new file mode 100644 index 00000000000..16c61c55769 --- /dev/null +++ b/ql/test/library-tests/semmle/go/frameworks/Beego/OpenRedirect.expected @@ -0,0 +1,11 @@ +edges +nodes +| test.go:246:13:246:34 | call to GetString | semmle.label | call to GetString | +| test.go:247:20:247:41 | call to GetString | semmle.label | call to GetString | +| test.go:310:13:310:27 | call to URI | semmle.label | call to URI | +| test.go:310:13:310:27 | call to URI | semmle.label | call to URI | +| test.go:311:20:311:34 | call to URL | semmle.label | call to URL | +| test.go:311:20:311:34 | call to URL | semmle.label | call to URL | +#select +| test.go:246:13:246:34 | call to GetString | test.go:246:13:246:34 | call to GetString | test.go:246:13:246:34 | call to GetString | Untrusted URL redirection due to $@. | test.go:246:13:246:34 | call to GetString | user-provided value | +| test.go:247:20:247:41 | call to GetString | test.go:247:20:247:41 | call to GetString | test.go:247:20:247:41 | call to GetString | Untrusted URL redirection due to $@. | test.go:247:20:247:41 | call to GetString | user-provided value | diff --git a/ql/test/library-tests/semmle/go/frameworks/Beego/OpenRedirect.qlref b/ql/test/library-tests/semmle/go/frameworks/Beego/OpenRedirect.qlref new file mode 100644 index 00000000000..0f1a7477825 --- /dev/null +++ b/ql/test/library-tests/semmle/go/frameworks/Beego/OpenRedirect.qlref @@ -0,0 +1 @@ +Security/CWE-601/OpenUrlRedirect.ql diff --git a/ql/test/library-tests/semmle/go/frameworks/Beego/ReflectedXss.expected b/ql/test/library-tests/semmle/go/frameworks/Beego/ReflectedXss.expected new file mode 100644 index 00000000000..a33c31b8d63 --- /dev/null +++ b/ql/test/library-tests/semmle/go/frameworks/Beego/ReflectedXss.expected @@ -0,0 +1,245 @@ +edges +| test.go:26:6:26:10 | definition of bound : bindMe | test.go:28:13:28:30 | type conversion | +| test.go:26:6:26:10 | definition of bound : bindMe | test.go:29:13:29:27 | type conversion | +| test.go:26:6:26:10 | definition of bound : bindMe | test.go:30:13:30:29 | type conversion | +| test.go:26:6:26:10 | definition of bound : bindMe | test.go:30:20:30:26 | selection of c : subBindMe | +| test.go:30:20:30:26 | selection of c : subBindMe | test.go:30:13:30:29 | type conversion | +| test.go:35:20:35:42 | call to Cookie : string | test.go:35:13:35:43 | type conversion | +| test.go:40:20:40:31 | call to Data : map type | test.go:40:13:40:52 | type conversion | +| test.go:45:20:45:43 | call to GetData : interface type | test.go:45:13:45:53 | type conversion | +| test.go:50:20:50:42 | call to Header : string | test.go:50:13:50:43 | type conversion | +| test.go:55:20:55:41 | call to Param : string | test.go:55:13:55:42 | type conversion | +| test.go:60:20:60:33 | call to Params : map type | test.go:60:13:60:45 | type conversion | +| test.go:65:20:65:41 | call to Query : string | test.go:65:13:65:42 | type conversion | +| test.go:70:20:70:32 | call to Refer : string | test.go:70:13:70:33 | type conversion | +| test.go:75:20:75:34 | call to Referer : string | test.go:75:13:75:35 | type conversion | +| test.go:80:20:80:30 | call to URI : string | test.go:80:13:80:31 | type conversion | +| test.go:85:20:85:30 | call to URL : string | test.go:85:13:85:31 | type conversion | +| test.go:90:20:90:36 | call to UserAgent : string | test.go:90:13:90:37 | type conversion | +| test.go:95:14:95:25 | call to Data : map type | test.go:95:14:95:45 | type assertion | +| test.go:107:14:107:25 | call to Data : map type | test.go:107:14:107:45 | type assertion | +| test.go:119:14:119:25 | call to Data : map type | test.go:119:14:119:45 | type assertion | +| test.go:136:23:136:42 | call to Data : map type | test.go:136:23:136:62 | type assertion | +| test.go:192:15:192:26 | call to Data : map type | test.go:193:14:193:55 | type conversion | +| test.go:192:15:192:26 | call to Data : map type | test.go:194:14:194:58 | type conversion | +| test.go:192:15:192:26 | call to Data : map type | test.go:196:14:196:28 | type assertion | +| test.go:192:15:192:26 | call to Data : map type | test.go:197:14:197:55 | type conversion | +| test.go:192:15:192:26 | call to Data : map type | test.go:198:14:198:59 | type conversion | +| test.go:201:18:201:33 | selection of Form : Values | test.go:202:14:202:28 | type conversion | +| test.go:216:2:216:34 | ... := ...[0] : File | test.go:219:14:219:20 | content | +| test.go:216:2:216:34 | ... := ...[1] : pointer type | test.go:217:14:217:32 | type conversion | +| test.go:216:2:216:34 | ... := ...[1] : pointer type | test.go:217:21:217:22 | implicit dereference : FileHeader | +| test.go:217:21:217:22 | implicit dereference : FileHeader | test.go:217:14:217:32 | type conversion | +| test.go:217:21:217:22 | implicit dereference : FileHeader | test.go:217:21:217:22 | implicit dereference : FileHeader | +| test.go:221:2:221:40 | ... := ...[0] : slice type | test.go:222:14:222:38 | type conversion | +| test.go:221:2:221:40 | ... := ...[0] : slice type | test.go:222:21:222:28 | implicit dereference : FileHeader | +| test.go:222:21:222:28 | implicit dereference : FileHeader | test.go:222:14:222:38 | type conversion | +| test.go:222:21:222:28 | implicit dereference : FileHeader | test.go:222:21:222:28 | implicit dereference : FileHeader | +| test.go:224:7:224:28 | call to GetString : string | test.go:225:14:225:22 | type conversion | +| test.go:227:8:227:35 | call to GetStrings : slice type | test.go:228:14:228:26 | type conversion | +| test.go:230:9:230:17 | call to Input : Values | test.go:231:14:231:27 | type conversion | +| test.go:233:6:233:8 | definition of str : myStruct | test.go:235:14:235:30 | type conversion | +| test.go:239:15:239:36 | call to GetString : string | test.go:242:21:242:29 | untrusted | +| test.go:252:23:252:44 | call to GetCookie : string | test.go:252:16:252:45 | type conversion | +| test.go:263:62:263:83 | call to GetCookie : string | test.go:263:55:263:84 | type conversion | +| test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:276:21:276:61 | call to GetDisplayString | +| test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:276:44:276:51 | implicit dereference : FileHeader | +| test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:277:21:277:83 | implicit dereference : FileHeader | +| test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:277:21:277:92 | selection of Filename | +| test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:278:21:278:87 | implicit dereference : FileHeader | +| test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:278:21:278:96 | selection of Filename | +| test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:283:3:285:71 | implicit dereference : FileHeader | +| test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:283:3:285:80 | selection of Filename | +| test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:286:21:286:92 | implicit dereference : FileHeader | +| test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:286:21:286:101 | selection of Filename | +| test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:287:21:287:92 | implicit dereference : FileHeader | +| test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:287:21:287:101 | selection of Filename | +| test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:288:21:288:88 | implicit dereference : FileHeader | +| test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:288:21:288:97 | selection of Filename | +| test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:289:21:289:88 | implicit dereference : FileHeader | +| test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:289:21:289:97 | selection of Filename | +| test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:290:21:290:93 | implicit dereference : FileHeader | +| test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:290:21:290:102 | selection of Filename | +| test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:291:21:291:93 | implicit dereference : FileHeader | +| test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:291:21:291:102 | selection of Filename | +| test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:292:21:292:73 | implicit dereference : FileHeader | +| test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:292:21:292:82 | selection of Filename | +| test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:294:21:294:124 | implicit dereference : FileHeader | +| test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:294:21:294:133 | selection of Filename | +| test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:295:21:295:79 | implicit dereference : FileHeader | +| test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:295:21:295:88 | selection of Filename | +| test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:296:21:296:78 | implicit dereference : FileHeader | +| test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:296:21:296:87 | selection of Filename | +| test.go:276:44:276:51 | implicit dereference : FileHeader | test.go:276:21:276:61 | call to GetDisplayString | +| test.go:276:44:276:51 | implicit dereference : FileHeader | test.go:276:44:276:51 | implicit dereference : FileHeader | +| test.go:277:21:277:83 | implicit dereference : FileHeader | test.go:277:21:277:92 | selection of Filename | +| test.go:278:21:278:87 | implicit dereference : FileHeader | test.go:278:21:278:96 | selection of Filename | +| test.go:283:3:285:71 | implicit dereference : FileHeader | test.go:283:3:285:80 | selection of Filename | +| test.go:286:21:286:92 | implicit dereference : FileHeader | test.go:286:21:286:101 | selection of Filename | +| test.go:287:21:287:92 | implicit dereference : FileHeader | test.go:287:21:287:101 | selection of Filename | +| test.go:288:21:288:88 | implicit dereference : FileHeader | test.go:288:21:288:97 | selection of Filename | +| test.go:289:21:289:88 | implicit dereference : FileHeader | test.go:289:21:289:97 | selection of Filename | +| test.go:290:21:290:93 | implicit dereference : FileHeader | test.go:290:21:290:102 | selection of Filename | +| test.go:291:21:291:93 | implicit dereference : FileHeader | test.go:291:21:291:102 | selection of Filename | +| test.go:292:21:292:73 | implicit dereference : FileHeader | test.go:292:21:292:82 | selection of Filename | +| test.go:294:21:294:124 | implicit dereference : FileHeader | test.go:294:21:294:133 | selection of Filename | +| test.go:295:21:295:79 | implicit dereference : FileHeader | test.go:295:21:295:88 | selection of Filename | +| test.go:296:21:296:78 | implicit dereference : FileHeader | test.go:296:21:296:87 | selection of Filename | +| test.go:302:15:302:36 | call to GetString : string | test.go:304:21:304:48 | type assertion | +| test.go:302:15:302:36 | call to GetString : string | test.go:305:21:305:52 | type assertion | +nodes +| test.go:26:6:26:10 | definition of bound : bindMe | semmle.label | definition of bound : bindMe | +| test.go:28:13:28:30 | type conversion | semmle.label | type conversion | +| test.go:29:13:29:27 | type conversion | semmle.label | type conversion | +| test.go:30:13:30:29 | type conversion | semmle.label | type conversion | +| test.go:30:20:30:26 | selection of c : subBindMe | semmle.label | selection of c : subBindMe | +| test.go:35:13:35:43 | type conversion | semmle.label | type conversion | +| test.go:35:20:35:42 | call to Cookie : string | semmle.label | call to Cookie : string | +| test.go:40:13:40:52 | type conversion | semmle.label | type conversion | +| test.go:40:20:40:31 | call to Data : map type | semmle.label | call to Data : map type | +| test.go:45:13:45:53 | type conversion | semmle.label | type conversion | +| test.go:45:20:45:43 | call to GetData : interface type | semmle.label | call to GetData : interface type | +| test.go:50:13:50:43 | type conversion | semmle.label | type conversion | +| test.go:50:20:50:42 | call to Header : string | semmle.label | call to Header : string | +| test.go:55:13:55:42 | type conversion | semmle.label | type conversion | +| test.go:55:20:55:41 | call to Param : string | semmle.label | call to Param : string | +| test.go:60:13:60:45 | type conversion | semmle.label | type conversion | +| test.go:60:20:60:33 | call to Params : map type | semmle.label | call to Params : map type | +| test.go:65:13:65:42 | type conversion | semmle.label | type conversion | +| test.go:65:20:65:41 | call to Query : string | semmle.label | call to Query : string | +| test.go:70:13:70:33 | type conversion | semmle.label | type conversion | +| test.go:70:20:70:32 | call to Refer : string | semmle.label | call to Refer : string | +| test.go:75:13:75:35 | type conversion | semmle.label | type conversion | +| test.go:75:20:75:34 | call to Referer : string | semmle.label | call to Referer : string | +| test.go:80:13:80:31 | type conversion | semmle.label | type conversion | +| test.go:80:20:80:30 | call to URI : string | semmle.label | call to URI : string | +| test.go:85:13:85:31 | type conversion | semmle.label | type conversion | +| test.go:85:20:85:30 | call to URL : string | semmle.label | call to URL : string | +| test.go:90:13:90:37 | type conversion | semmle.label | type conversion | +| test.go:90:20:90:36 | call to UserAgent : string | semmle.label | call to UserAgent : string | +| test.go:95:14:95:25 | call to Data : map type | semmle.label | call to Data : map type | +| test.go:95:14:95:45 | type assertion | semmle.label | type assertion | +| test.go:107:14:107:25 | call to Data : map type | semmle.label | call to Data : map type | +| test.go:107:14:107:45 | type assertion | semmle.label | type assertion | +| test.go:119:14:119:25 | call to Data : map type | semmle.label | call to Data : map type | +| test.go:119:14:119:45 | type assertion | semmle.label | type assertion | +| test.go:136:23:136:42 | call to Data : map type | semmle.label | call to Data : map type | +| test.go:136:23:136:62 | type assertion | semmle.label | type assertion | +| test.go:192:15:192:26 | call to Data : map type | semmle.label | call to Data : map type | +| test.go:193:14:193:55 | type conversion | semmle.label | type conversion | +| test.go:194:14:194:58 | type conversion | semmle.label | type conversion | +| test.go:196:14:196:28 | type assertion | semmle.label | type assertion | +| test.go:197:14:197:55 | type conversion | semmle.label | type conversion | +| test.go:198:14:198:59 | type conversion | semmle.label | type conversion | +| test.go:201:18:201:33 | selection of Form : Values | semmle.label | selection of Form : Values | +| test.go:202:14:202:28 | type conversion | semmle.label | type conversion | +| test.go:216:2:216:34 | ... := ...[0] : File | semmle.label | ... := ...[0] : File | +| test.go:216:2:216:34 | ... := ...[1] : pointer type | semmle.label | ... := ...[1] : pointer type | +| test.go:217:14:217:32 | type conversion | semmle.label | type conversion | +| test.go:217:21:217:22 | implicit dereference : FileHeader | semmle.label | implicit dereference : FileHeader | +| test.go:219:14:219:20 | content | semmle.label | content | +| test.go:221:2:221:40 | ... := ...[0] : slice type | semmle.label | ... := ...[0] : slice type | +| test.go:222:14:222:38 | type conversion | semmle.label | type conversion | +| test.go:222:21:222:28 | implicit dereference : FileHeader | semmle.label | implicit dereference : FileHeader | +| test.go:224:7:224:28 | call to GetString : string | semmle.label | call to GetString : string | +| test.go:225:14:225:22 | type conversion | semmle.label | type conversion | +| test.go:227:8:227:35 | call to GetStrings : slice type | semmle.label | call to GetStrings : slice type | +| test.go:228:14:228:26 | type conversion | semmle.label | type conversion | +| test.go:230:9:230:17 | call to Input : Values | semmle.label | call to Input : Values | +| test.go:231:14:231:27 | type conversion | semmle.label | type conversion | +| test.go:233:6:233:8 | definition of str : myStruct | semmle.label | definition of str : myStruct | +| test.go:235:14:235:30 | type conversion | semmle.label | type conversion | +| test.go:239:15:239:36 | call to GetString : string | semmle.label | call to GetString : string | +| test.go:242:21:242:29 | untrusted | semmle.label | untrusted | +| test.go:252:16:252:45 | type conversion | semmle.label | type conversion | +| test.go:252:23:252:44 | call to GetCookie : string | semmle.label | call to GetCookie : string | +| test.go:257:16:257:37 | call to GetCookie | semmle.label | call to GetCookie | +| test.go:258:15:258:41 | call to GetCookie | semmle.label | call to GetCookie | +| test.go:263:55:263:84 | type conversion | semmle.label | type conversion | +| test.go:263:62:263:83 | call to GetCookie : string | semmle.label | call to GetCookie : string | +| test.go:268:2:268:40 | ... := ...[0] : slice type | semmle.label | ... := ...[0] : slice type | +| test.go:276:21:276:61 | call to GetDisplayString | semmle.label | call to GetDisplayString | +| test.go:276:44:276:51 | implicit dereference : FileHeader | semmle.label | implicit dereference : FileHeader | +| test.go:277:21:277:83 | implicit dereference : FileHeader | semmle.label | implicit dereference : FileHeader | +| test.go:277:21:277:92 | selection of Filename | semmle.label | selection of Filename | +| test.go:278:21:278:87 | implicit dereference : FileHeader | semmle.label | implicit dereference : FileHeader | +| test.go:278:21:278:96 | selection of Filename | semmle.label | selection of Filename | +| test.go:283:3:285:71 | implicit dereference : FileHeader | semmle.label | implicit dereference : FileHeader | +| test.go:283:3:285:80 | selection of Filename | semmle.label | selection of Filename | +| test.go:286:21:286:92 | implicit dereference : FileHeader | semmle.label | implicit dereference : FileHeader | +| test.go:286:21:286:101 | selection of Filename | semmle.label | selection of Filename | +| test.go:287:21:287:92 | implicit dereference : FileHeader | semmle.label | implicit dereference : FileHeader | +| test.go:287:21:287:101 | selection of Filename | semmle.label | selection of Filename | +| test.go:288:21:288:88 | implicit dereference : FileHeader | semmle.label | implicit dereference : FileHeader | +| test.go:288:21:288:97 | selection of Filename | semmle.label | selection of Filename | +| test.go:289:21:289:88 | implicit dereference : FileHeader | semmle.label | implicit dereference : FileHeader | +| test.go:289:21:289:97 | selection of Filename | semmle.label | selection of Filename | +| test.go:290:21:290:93 | implicit dereference : FileHeader | semmle.label | implicit dereference : FileHeader | +| test.go:290:21:290:102 | selection of Filename | semmle.label | selection of Filename | +| test.go:291:21:291:93 | implicit dereference : FileHeader | semmle.label | implicit dereference : FileHeader | +| test.go:291:21:291:102 | selection of Filename | semmle.label | selection of Filename | +| test.go:292:21:292:73 | implicit dereference : FileHeader | semmle.label | implicit dereference : FileHeader | +| test.go:292:21:292:82 | selection of Filename | semmle.label | selection of Filename | +| test.go:294:21:294:124 | implicit dereference : FileHeader | semmle.label | implicit dereference : FileHeader | +| test.go:294:21:294:133 | selection of Filename | semmle.label | selection of Filename | +| test.go:295:21:295:79 | implicit dereference : FileHeader | semmle.label | implicit dereference : FileHeader | +| test.go:295:21:295:88 | selection of Filename | semmle.label | selection of Filename | +| test.go:296:21:296:78 | implicit dereference : FileHeader | semmle.label | implicit dereference : FileHeader | +| test.go:296:21:296:87 | selection of Filename | semmle.label | selection of Filename | +| test.go:302:15:302:36 | call to GetString : string | semmle.label | call to GetString : string | +| test.go:304:21:304:48 | type assertion | semmle.label | type assertion | +| test.go:305:21:305:52 | type assertion | semmle.label | type assertion | +#select +| test.go:28:13:28:30 | type conversion | test.go:26:6:26:10 | definition of bound : bindMe | test.go:28:13:28:30 | type conversion | Cross-site scripting vulnerability due to $@. | test.go:26:6:26:10 | definition of bound | user-provided value | +| test.go:29:13:29:27 | type conversion | test.go:26:6:26:10 | definition of bound : bindMe | test.go:29:13:29:27 | type conversion | Cross-site scripting vulnerability due to $@. | test.go:26:6:26:10 | definition of bound | user-provided value | +| test.go:30:13:30:29 | type conversion | test.go:26:6:26:10 | definition of bound : bindMe | test.go:30:13:30:29 | type conversion | Cross-site scripting vulnerability due to $@. | test.go:26:6:26:10 | definition of bound | user-provided value | +| test.go:35:13:35:43 | type conversion | test.go:35:20:35:42 | call to Cookie : string | test.go:35:13:35:43 | type conversion | Cross-site scripting vulnerability due to $@. | test.go:35:20:35:42 | call to Cookie | user-provided value | +| test.go:40:13:40:52 | type conversion | test.go:40:20:40:31 | call to Data : map type | test.go:40:13:40:52 | type conversion | Cross-site scripting vulnerability due to $@. | test.go:40:20:40:31 | call to Data | user-provided value | +| test.go:45:13:45:53 | type conversion | test.go:45:20:45:43 | call to GetData : interface type | test.go:45:13:45:53 | type conversion | Cross-site scripting vulnerability due to $@. | test.go:45:20:45:43 | call to GetData | user-provided value | +| test.go:50:13:50:43 | type conversion | test.go:50:20:50:42 | call to Header : string | test.go:50:13:50:43 | type conversion | Cross-site scripting vulnerability due to $@. | test.go:50:20:50:42 | call to Header | user-provided value | +| test.go:55:13:55:42 | type conversion | test.go:55:20:55:41 | call to Param : string | test.go:55:13:55:42 | type conversion | Cross-site scripting vulnerability due to $@. | test.go:55:20:55:41 | call to Param | user-provided value | +| test.go:60:13:60:45 | type conversion | test.go:60:20:60:33 | call to Params : map type | test.go:60:13:60:45 | type conversion | Cross-site scripting vulnerability due to $@. | test.go:60:20:60:33 | call to Params | user-provided value | +| test.go:65:13:65:42 | type conversion | test.go:65:20:65:41 | call to Query : string | test.go:65:13:65:42 | type conversion | Cross-site scripting vulnerability due to $@. | test.go:65:20:65:41 | call to Query | user-provided value | +| test.go:70:13:70:33 | type conversion | test.go:70:20:70:32 | call to Refer : string | test.go:70:13:70:33 | type conversion | Cross-site scripting vulnerability due to $@. | test.go:70:20:70:32 | call to Refer | user-provided value | +| test.go:75:13:75:35 | type conversion | test.go:75:20:75:34 | call to Referer : string | test.go:75:13:75:35 | type conversion | Cross-site scripting vulnerability due to $@. | test.go:75:20:75:34 | call to Referer | user-provided value | +| test.go:80:13:80:31 | type conversion | test.go:80:20:80:30 | call to URI : string | test.go:80:13:80:31 | type conversion | Cross-site scripting vulnerability due to $@. | test.go:80:20:80:30 | call to URI | user-provided value | +| test.go:85:13:85:31 | type conversion | test.go:85:20:85:30 | call to URL : string | test.go:85:13:85:31 | type conversion | Cross-site scripting vulnerability due to $@. | test.go:85:20:85:30 | call to URL | user-provided value | +| test.go:90:13:90:37 | type conversion | test.go:90:20:90:36 | call to UserAgent : string | test.go:90:13:90:37 | type conversion | Cross-site scripting vulnerability due to $@. | test.go:90:20:90:36 | call to UserAgent | user-provided value | +| test.go:95:14:95:45 | type assertion | test.go:95:14:95:25 | call to Data : map type | test.go:95:14:95:45 | type assertion | Cross-site scripting vulnerability due to $@. | test.go:95:14:95:25 | call to Data | user-provided value | +| test.go:107:14:107:45 | type assertion | test.go:107:14:107:25 | call to Data : map type | test.go:107:14:107:45 | type assertion | Cross-site scripting vulnerability due to $@. | test.go:107:14:107:25 | call to Data | user-provided value | +| test.go:119:14:119:45 | type assertion | test.go:119:14:119:25 | call to Data : map type | test.go:119:14:119:45 | type assertion | Cross-site scripting vulnerability due to $@. | test.go:119:14:119:25 | call to Data | user-provided value | +| test.go:136:23:136:62 | type assertion | test.go:136:23:136:42 | call to Data : map type | test.go:136:23:136:62 | type assertion | Cross-site scripting vulnerability due to $@. | test.go:136:23:136:42 | call to Data | user-provided value | +| test.go:193:14:193:55 | type conversion | test.go:192:15:192:26 | call to Data : map type | test.go:193:14:193:55 | type conversion | Cross-site scripting vulnerability due to $@. | test.go:192:15:192:26 | call to Data | user-provided value | +| test.go:194:14:194:58 | type conversion | test.go:192:15:192:26 | call to Data : map type | test.go:194:14:194:58 | type conversion | Cross-site scripting vulnerability due to $@. | test.go:192:15:192:26 | call to Data | user-provided value | +| test.go:196:14:196:28 | type assertion | test.go:192:15:192:26 | call to Data : map type | test.go:196:14:196:28 | type assertion | Cross-site scripting vulnerability due to $@. | test.go:192:15:192:26 | call to Data | user-provided value | +| test.go:197:14:197:55 | type conversion | test.go:192:15:192:26 | call to Data : map type | test.go:197:14:197:55 | type conversion | Cross-site scripting vulnerability due to $@. | test.go:192:15:192:26 | call to Data | user-provided value | +| test.go:198:14:198:59 | type conversion | test.go:192:15:192:26 | call to Data : map type | test.go:198:14:198:59 | type conversion | Cross-site scripting vulnerability due to $@. | test.go:192:15:192:26 | call to Data | user-provided value | +| test.go:202:14:202:28 | type conversion | test.go:201:18:201:33 | selection of Form : Values | test.go:202:14:202:28 | type conversion | Cross-site scripting vulnerability due to $@. | test.go:201:18:201:33 | selection of Form | user-provided value | +| test.go:217:14:217:32 | type conversion | test.go:216:2:216:34 | ... := ...[1] : pointer type | test.go:217:14:217:32 | type conversion | Cross-site scripting vulnerability due to $@. | test.go:216:2:216:34 | ... := ...[1] | user-provided value | +| test.go:219:14:219:20 | content | test.go:216:2:216:34 | ... := ...[0] : File | test.go:219:14:219:20 | content | Cross-site scripting vulnerability due to $@. | test.go:216:2:216:34 | ... := ...[0] | user-provided value | +| test.go:222:14:222:38 | type conversion | test.go:221:2:221:40 | ... := ...[0] : slice type | test.go:222:14:222:38 | type conversion | Cross-site scripting vulnerability due to $@. | test.go:221:2:221:40 | ... := ...[0] | user-provided value | +| test.go:225:14:225:22 | type conversion | test.go:224:7:224:28 | call to GetString : string | test.go:225:14:225:22 | type conversion | Cross-site scripting vulnerability due to $@. | test.go:224:7:224:28 | call to GetString | user-provided value | +| test.go:228:14:228:26 | type conversion | test.go:227:8:227:35 | call to GetStrings : slice type | test.go:228:14:228:26 | type conversion | Cross-site scripting vulnerability due to $@. | test.go:227:8:227:35 | call to GetStrings | user-provided value | +| test.go:231:14:231:27 | type conversion | test.go:230:9:230:17 | call to Input : Values | test.go:231:14:231:27 | type conversion | Cross-site scripting vulnerability due to $@. | test.go:230:9:230:17 | call to Input | user-provided value | +| test.go:235:14:235:30 | type conversion | test.go:233:6:233:8 | definition of str : myStruct | test.go:235:14:235:30 | type conversion | Cross-site scripting vulnerability due to $@. | test.go:233:6:233:8 | definition of str | user-provided value | +| test.go:242:21:242:29 | untrusted | test.go:239:15:239:36 | call to GetString : string | test.go:242:21:242:29 | untrusted | Cross-site scripting vulnerability due to $@. | test.go:239:15:239:36 | call to GetString | user-provided value | +| test.go:252:16:252:45 | type conversion | test.go:252:23:252:44 | call to GetCookie : string | test.go:252:16:252:45 | type conversion | Cross-site scripting vulnerability due to $@. | test.go:252:23:252:44 | call to GetCookie | user-provided value | +| test.go:257:16:257:37 | call to GetCookie | test.go:257:16:257:37 | call to GetCookie | test.go:257:16:257:37 | call to GetCookie | Cross-site scripting vulnerability due to $@. | test.go:257:16:257:37 | call to GetCookie | user-provided value | +| test.go:258:15:258:41 | call to GetCookie | test.go:258:15:258:41 | call to GetCookie | test.go:258:15:258:41 | call to GetCookie | Cross-site scripting vulnerability due to $@. | test.go:258:15:258:41 | call to GetCookie | user-provided value | +| test.go:263:55:263:84 | type conversion | test.go:263:62:263:83 | call to GetCookie : string | test.go:263:55:263:84 | type conversion | Cross-site scripting vulnerability due to $@. | test.go:263:62:263:83 | call to GetCookie | user-provided value | +| test.go:276:21:276:61 | call to GetDisplayString | test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:276:21:276:61 | call to GetDisplayString | Cross-site scripting vulnerability due to $@. | test.go:268:2:268:40 | ... := ...[0] | user-provided value | +| test.go:277:21:277:92 | selection of Filename | test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:277:21:277:92 | selection of Filename | Cross-site scripting vulnerability due to $@. | test.go:268:2:268:40 | ... := ...[0] | user-provided value | +| test.go:278:21:278:96 | selection of Filename | test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:278:21:278:96 | selection of Filename | Cross-site scripting vulnerability due to $@. | test.go:268:2:268:40 | ... := ...[0] | user-provided value | +| test.go:283:3:285:80 | selection of Filename | test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:283:3:285:80 | selection of Filename | Cross-site scripting vulnerability due to $@. | test.go:268:2:268:40 | ... := ...[0] | user-provided value | +| test.go:286:21:286:101 | selection of Filename | test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:286:21:286:101 | selection of Filename | Cross-site scripting vulnerability due to $@. | test.go:268:2:268:40 | ... := ...[0] | user-provided value | +| test.go:287:21:287:101 | selection of Filename | test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:287:21:287:101 | selection of Filename | Cross-site scripting vulnerability due to $@. | test.go:268:2:268:40 | ... := ...[0] | user-provided value | +| test.go:288:21:288:97 | selection of Filename | test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:288:21:288:97 | selection of Filename | Cross-site scripting vulnerability due to $@. | test.go:268:2:268:40 | ... := ...[0] | user-provided value | +| test.go:289:21:289:97 | selection of Filename | test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:289:21:289:97 | selection of Filename | Cross-site scripting vulnerability due to $@. | test.go:268:2:268:40 | ... := ...[0] | user-provided value | +| test.go:290:21:290:102 | selection of Filename | test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:290:21:290:102 | selection of Filename | Cross-site scripting vulnerability due to $@. | test.go:268:2:268:40 | ... := ...[0] | user-provided value | +| test.go:291:21:291:102 | selection of Filename | test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:291:21:291:102 | selection of Filename | Cross-site scripting vulnerability due to $@. | test.go:268:2:268:40 | ... := ...[0] | user-provided value | +| test.go:292:21:292:82 | selection of Filename | test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:292:21:292:82 | selection of Filename | Cross-site scripting vulnerability due to $@. | test.go:268:2:268:40 | ... := ...[0] | user-provided value | +| test.go:294:21:294:133 | selection of Filename | test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:294:21:294:133 | selection of Filename | Cross-site scripting vulnerability due to $@. | test.go:268:2:268:40 | ... := ...[0] | user-provided value | +| test.go:295:21:295:88 | selection of Filename | test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:295:21:295:88 | selection of Filename | Cross-site scripting vulnerability due to $@. | test.go:268:2:268:40 | ... := ...[0] | user-provided value | +| test.go:296:21:296:87 | selection of Filename | test.go:268:2:268:40 | ... := ...[0] : slice type | test.go:296:21:296:87 | selection of Filename | Cross-site scripting vulnerability due to $@. | test.go:268:2:268:40 | ... := ...[0] | user-provided value | +| test.go:304:21:304:48 | type assertion | test.go:302:15:302:36 | call to GetString : string | test.go:304:21:304:48 | type assertion | Cross-site scripting vulnerability due to $@. | test.go:302:15:302:36 | call to GetString | user-provided value | +| test.go:305:21:305:52 | type assertion | test.go:302:15:302:36 | call to GetString : string | test.go:305:21:305:52 | type assertion | Cross-site scripting vulnerability due to $@. | test.go:302:15:302:36 | call to GetString | user-provided value | diff --git a/ql/test/library-tests/semmle/go/frameworks/Beego/ReflectedXss.qlref b/ql/test/library-tests/semmle/go/frameworks/Beego/ReflectedXss.qlref new file mode 100644 index 00000000000..e0efe102416 --- /dev/null +++ b/ql/test/library-tests/semmle/go/frameworks/Beego/ReflectedXss.qlref @@ -0,0 +1 @@ +Security/CWE-079/ReflectedXss.ql diff --git a/ql/test/library-tests/semmle/go/frameworks/Beego/TaintedPath.expected b/ql/test/library-tests/semmle/go/frameworks/Beego/TaintedPath.expected new file mode 100644 index 00000000000..1b3ac71fe8d --- /dev/null +++ b/ql/test/library-tests/semmle/go/frameworks/Beego/TaintedPath.expected @@ -0,0 +1,13 @@ +edges +| test.go:208:15:208:26 | call to Data : map type | test.go:209:18:209:26 | untrusted | +| test.go:208:15:208:26 | call to Data : map type | test.go:210:10:210:18 | untrusted | +| test.go:208:15:208:26 | call to Data : map type | test.go:211:35:211:43 | untrusted | +nodes +| test.go:208:15:208:26 | call to Data : map type | semmle.label | call to Data : map type | +| test.go:209:18:209:26 | untrusted | semmle.label | untrusted | +| test.go:210:10:210:18 | untrusted | semmle.label | untrusted | +| test.go:211:35:211:43 | untrusted | semmle.label | untrusted | +#select +| test.go:209:18:209:26 | untrusted | test.go:208:15:208:26 | call to Data : map type | test.go:209:18:209:26 | untrusted | This path depends on $@. | test.go:208:15:208:26 | call to Data | a user-provided value | +| test.go:210:10:210:18 | untrusted | test.go:208:15:208:26 | call to Data : map type | test.go:210:10:210:18 | untrusted | This path depends on $@. | test.go:208:15:208:26 | call to Data | a user-provided value | +| test.go:211:35:211:43 | untrusted | test.go:208:15:208:26 | call to Data : map type | test.go:211:35:211:43 | untrusted | This path depends on $@. | test.go:208:15:208:26 | call to Data | a user-provided value | diff --git a/ql/test/library-tests/semmle/go/frameworks/Beego/TaintedPath.qlref b/ql/test/library-tests/semmle/go/frameworks/Beego/TaintedPath.qlref new file mode 100644 index 00000000000..53d53cb8dc5 --- /dev/null +++ b/ql/test/library-tests/semmle/go/frameworks/Beego/TaintedPath.qlref @@ -0,0 +1 @@ +Security/CWE-022/TaintedPath.ql diff --git a/ql/test/library-tests/semmle/go/frameworks/Beego/go.mod b/ql/test/library-tests/semmle/go/frameworks/Beego/go.mod new file mode 100644 index 00000000000..10fdeed3e35 --- /dev/null +++ b/ql/test/library-tests/semmle/go/frameworks/Beego/go.mod @@ -0,0 +1,7 @@ +module test/beego + +go 1.14 + +require ( + github.com/astaxie/beego v1.12.3 +) diff --git a/ql/test/library-tests/semmle/go/frameworks/Beego/test.go b/ql/test/library-tests/semmle/go/frameworks/Beego/test.go new file mode 100644 index 00000000000..b5953d8e768 --- /dev/null +++ b/ql/test/library-tests/semmle/go/frameworks/Beego/test.go @@ -0,0 +1,312 @@ +package test + +import ( + "github.com/astaxie/beego" + "github.com/astaxie/beego/context" + "github.com/astaxie/beego/logs" + "github.com/astaxie/beego/utils" + "io/ioutil" + "mime/multipart" + "net/http" + "os" +) + +type subBindMe struct { + z string +} + +type bindMe struct { + a []string + b string + c subBindMe +} + +// BAD: echoing untrusted data to an `http.ResponseWriter` +func xssFromBind(input *context.BeegoInput, sink http.ResponseWriter) { + var bound bindMe + input.Bind(bound, "someKey") + sink.Write([]byte(bound.a[0])) + sink.Write([]byte(bound.b)) + sink.Write([]byte(bound.c.z)) +} + +// BAD: echoing untrusted data to an `http.ResponseWriter` +func xssFromCookie(input *context.BeegoInput, sink http.ResponseWriter) { + sink.Write([]byte(input.Cookie("someKey"))) +} + +// BAD: echoing untrusted data to an `http.ResponseWriter` +func xssFromData(input *context.BeegoInput, sink http.ResponseWriter) { + sink.Write([]byte(input.Data()["someKey"].(string))) +} + +// BAD: echoing untrusted data to an `http.ResponseWriter` +func xssFromGetData(input *context.BeegoInput, sink http.ResponseWriter) { + sink.Write([]byte(input.GetData("someKey").(string))) +} + +// BAD: echoing untrusted data to an `http.ResponseWriter` +func xssFromHeader(input *context.BeegoInput, sink http.ResponseWriter) { + sink.Write([]byte(input.Header("someKey"))) +} + +// BAD: echoing untrusted data to an `http.ResponseWriter` +func xssFromParam(input *context.BeegoInput, sink http.ResponseWriter) { + sink.Write([]byte(input.Param("someKey"))) +} + +// BAD: echoing untrusted data to an `http.ResponseWriter` +func xssFromParams(input *context.BeegoInput, sink http.ResponseWriter) { + sink.Write([]byte(input.Params()["someKey"])) +} + +// BAD: echoing untrusted data to an `http.ResponseWriter` +func xssFromQuery(input *context.BeegoInput, sink http.ResponseWriter) { + sink.Write([]byte(input.Query("someKey"))) +} + +// BAD: echoing untrusted data to an `http.ResponseWriter` +func xssFromRefer(input *context.BeegoInput, sink http.ResponseWriter) { + sink.Write([]byte(input.Refer())) +} + +// BAD: echoing untrusted data to an `http.ResponseWriter` +func xssFromReferer(input *context.BeegoInput, sink http.ResponseWriter) { + sink.Write([]byte(input.Referer())) +} + +// BAD: echoing untrusted data to an `http.ResponseWriter` +func xssFromURI(input *context.BeegoInput, sink http.ResponseWriter) { + sink.Write([]byte(input.URI())) +} + +// BAD: echoing untrusted data to an `http.ResponseWriter` +func xssFromURL(input *context.BeegoInput, sink http.ResponseWriter) { + sink.Write([]byte(input.URL())) +} + +// BAD: echoing untrusted data to an `http.ResponseWriter` +func xssFromUserAgent(input *context.BeegoInput, sink http.ResponseWriter) { + sink.Write([]byte(input.UserAgent())) +} + +// BAD: with no obvious ContentType call we assume this could be text/html. +func echoToBodyNoContentType(input *context.BeegoInput, output *context.BeegoOutput) { + output.Body(input.Data()["someKey"].([]byte)) +} + +// OK: JSON can't (by itself) cause XSS +func echoToBodyContentTypeJson(input *context.BeegoInput, output *context.BeegoOutput) { + output.ContentType("application/json") + output.Body(input.Data()["someKey"].([]byte)) +} + +// BAD: echoing untrusted data with an HTML content type +func echoToBodyContentTypeHtml(input *context.BeegoInput, output *context.BeegoOutput) { + output.ContentType("text/html") + output.Body(input.Data()["someKey"].([]byte)) +} + +// OK: JSON can't (by itself) cause XSS +func echoToBodyContentTypeJsonUsingHeader(input *context.BeegoInput, output *context.BeegoOutput) { + output.Header("content-type", "application/json") + output.Body(input.Data()["someKey"].([]byte)) +} + +// BAD: echoing untrusted data with an HTML content type +func echoToBodyContentTypeHtmlUsingHeader(input *context.BeegoInput, output *context.BeegoOutput) { + output.Header("content-type", "text/html") + output.Body(input.Data()["someKey"].([]byte)) +} + +// OK: JSON and other non-HTML formats can't (by themselves) cause XSS +func echoToFixedContentTypeRoutines(input *context.BeegoInput, output *context.BeegoOutput) { + output.JSON(input.Data()["someKey"].(string), false, false) + output.JSONP(input.Data()["someKey"].(string), false) + output.ServeFormatted(input.Data()["someKey"].(string), false, false) + output.XML(input.Data()["someKey"].(string), false) + output.YAML(input.Data()["someKey"].(string)) +} + +// BAD: echoing untrusted data with an HTML content type +// This time using a more realistic context: registering a function using App.Post. +func echoToBodyContentTypeHtmlUsingHandler() { + beego.Post("", func(context *context.Context) { + context.Output.Header("content-type", "text/html") + context.Output.Body(context.Input.Data()["someKey"].([]byte)) + }) +} + +// OK: using beego.htmlQuote sanitizes. +func echoToBodySanitized(input *context.BeegoInput, output *context.BeegoOutput) { + output.Body([]byte(beego.Htmlquote(input.Data()["someKey"].(string)))) +} + +// BAD: logging something named "password". +func loggerTest(password string, logger *logs.BeeLogger) { + beego.Alert(password) + beego.Critical(password) + beego.Debug(password) + beego.Emergency(password) + beego.Error(password) + beego.Info(password) + beego.Informational(password) + beego.Notice(password) + beego.Trace(password) + beego.Warn(password) + beego.Warning(password) + logs.Alert(password) + logs.Critical(password) + logs.Debug(password) + logs.Emergency(password) + logs.Error(password) + logs.Info(password) + logs.Informational(password) + logs.Notice(password) + logs.Trace(password) + logs.Warn(password) + logs.Warning(password) + logger.Alert(password) + logger.Critical(password) + logger.Debug(password) + logger.Emergency(password) + logger.Error(password) + logger.Info(password) + logger.Informational(password) + logger.Notice(password) + logger.Trace(password) + logger.Warn(password) + logger.Warning(password) + utils.Display(password) +} + +type myStruct struct { + field string +} + +// BAD: echoing untrusted data, via various taint-propagating functions +func sanitizersTest(ctx *context.Context) { + input := ctx.Input + output := ctx.Output + + untrusted := input.Data()["someKey"] + output.Body([]byte(beego.HTML2str(untrusted.(string)))) + output.Body([]byte(beego.Htmlunquote(untrusted.(string)))) + mapVal, _ := beego.MapGet(untrusted.(map[string][]byte), "somekey") + output.Body(mapVal.([]byte)) + output.Body([]byte(beego.Str2html(untrusted.(string)))) + output.Body([]byte(beego.Substr(untrusted.(string), 1, 2))) + + var s myStruct + beego.ParseForm(ctx.Request.Form, s) + output.Body([]byte(s.field)) +} + +// BAD: using user-provided data as paths in file-system operations +func fsOpsTest(ctx *context.Context, c *beego.Controller, fs beego.FileSystem) { + input := ctx.Input + untrusted := input.Data()["someKey"].(string) + beego.Walk(nil, untrusted, func(path string, info os.FileInfo, err error) error { return nil }) + fs.Open(untrusted) + c.SaveToFile("someReceviedFile", untrusted) +} + +// BAD: echoing untrusted data, using various Controller sources +func controllerSourceTest(c *beego.Controller, output *context.BeegoOutput) { + f, fh, _ := c.GetFile("somename") + output.Body([]byte(fh.Filename)) + content, _ := ioutil.ReadAll(f) + output.Body(content) + + files, _ := c.GetFiles("someothername") + output.Body([]byte(files[0].Filename)) + + s := c.GetString("somekey") + output.Body([]byte(s)) + + ss := c.GetStrings("someotherkey") + output.Body([]byte(ss[0])) + + val := c.Input()["thirdkey"] + output.Body([]byte(val[0])) + + var str myStruct + c.ParseForm(str) + output.Body([]byte(str.field)) +} + +func controllerSinkTest(c *beego.Controller) { + untrusted := c.GetString("somekey") + c.SetData(untrusted) // GOOD: SetData always uses a non-html content-type, so no XSS risk + + c.CustomAbort(500, untrusted) // BAD: CustomAbort doesn't set a content-type, so there is an XSS risk +} + +func redirectTest(c *beego.Controller, ctx *context.Context) { + c.Redirect(c.GetString("somekey"), 304) // BAD: User-controlled redirect + ctx.Redirect(304, c.GetString("somekey")) // BAD: User-controlled redirect +} + +// BAD: echoing untrusted data, using Context source +func contextSourceTest(c *context.Context) { + c.Output.Body([]byte(c.GetCookie("somekey"))) +} + +// BAD: echoing untrusted data, using Context sinks +func contextSinkTest(c *context.Context) { + c.WriteString(c.GetCookie("somekey")) + c.Abort(500, c.GetCookie("someOtherKey")) +} + +// BAD: echoing untrusted data, using context.WriteBody as a propagator +func contextWriteBodyTest(c *context.Context) { + context.WriteBody("some/encoding", c.ResponseWriter, []byte(c.GetCookie("someKey"))) +} + +// BAD unless otherwise noted: echoing untrusted data, using various utils methods as propagators +func testUtilsPropagators(c *beego.Controller) { + files, _ := c.GetFiles("someothername") + genericFiles := make([]interface{}, len(files), len(files)) + for i := range files { + genericFiles[i] = files[i] + } + + untainted := make([]interface{}, 1, 1) + + c.CustomAbort(500, utils.GetDisplayString(files[0].Filename)) + c.CustomAbort(500, utils.SliceChunk(genericFiles, 1)[0][0].(*multipart.FileHeader).Filename) + c.CustomAbort(500, utils.SliceDiff(genericFiles, untainted)[0].(*multipart.FileHeader).Filename) + // GOOD: the tainted values are subtracted, so taint is not propagated + c.CustomAbort(500, utils.SliceDiff(untainted, genericFiles)[0].(*multipart.FileHeader).Filename) + c.CustomAbort( + 500, + utils.SliceFilter( + genericFiles, + func([]interface{}) bool { return true })[0].(*multipart.FileHeader).Filename) + c.CustomAbort(500, utils.SliceIntersect(genericFiles, untainted)[0].(*multipart.FileHeader).Filename) + c.CustomAbort(500, utils.SliceIntersect(untainted, genericFiles)[0].(*multipart.FileHeader).Filename) + c.CustomAbort(500, utils.SliceMerge(genericFiles, untainted)[0].(*multipart.FileHeader).Filename) + c.CustomAbort(500, utils.SliceMerge(untainted, genericFiles)[0].(*multipart.FileHeader).Filename) + c.CustomAbort(500, utils.SlicePad(untainted, 10, genericFiles[0])[0].(*multipart.FileHeader).Filename) + c.CustomAbort(500, utils.SlicePad(genericFiles, 10, untainted[0])[0].(*multipart.FileHeader).Filename) + c.CustomAbort(500, utils.SliceRand(genericFiles).(*multipart.FileHeader).Filename) + // Note this is misnamed -- it's a map operation, not a reduce + c.CustomAbort(500, utils.SliceReduce(genericFiles, func(x interface{}) interface{} { return x })[0].(*multipart.FileHeader).Filename) + c.CustomAbort(500, utils.SliceShuffle(genericFiles)[0].(*multipart.FileHeader).Filename) + c.CustomAbort(500, utils.SliceUnique(genericFiles)[0].(*multipart.FileHeader).Filename) +} + +// BAD: echoing untrusted data, using BeeMap as an intermediary +func testBeeMap(c *beego.Controller) { + bMap := utils.NewBeeMap() + untrusted := c.GetString("someKey") + bMap.Set("someKey", untrusted) + c.CustomAbort(500, bMap.Get("someKey").(string)) + c.CustomAbort(500, bMap.Items()["someKey"].(string)) +} + +// GOOD: using the input URL for a redirect operation +func testSafeRedirects(c *beego.Controller, ctx *context.Context) { + c.Redirect(ctx.Input.URI(), 304) + ctx.Redirect(304, ctx.Input.URL()) +} diff --git a/ql/test/library-tests/semmle/go/frameworks/Beego/vendor/github.com/astaxie/beego/context/stub.go b/ql/test/library-tests/semmle/go/frameworks/Beego/vendor/github.com/astaxie/beego/context/stub.go new file mode 100644 index 00000000000..7177b87aff5 --- /dev/null +++ b/ql/test/library-tests/semmle/go/frameworks/Beego/vendor/github.com/astaxie/beego/context/stub.go @@ -0,0 +1,355 @@ +// Code generated by depstubber. DO NOT EDIT +// This is a simple stub for github.com/astaxie/beego/context, strictly for use in testing. + +// See the LICENSE file for information about the licensing of the original library. +// Source: github.com/astaxie/beego/context (exports: BeegoInput,BeegoOutput,Context; functions: WriteBody) + +// Package context is a stub of github.com/astaxie/beego/context, generated by depstubber. +package context + +import ( + "bufio" + "io" + "net" + "net/http" + "reflect" + "time" +) + +type BeegoInput struct { + Context *Context + CruSession interface{} + RequestBody []byte + RunMethod string + RunController reflect.Type +} + +func (_ *BeegoInput) AcceptsHTML() bool { + return false +} + +func (_ *BeegoInput) AcceptsJSON() bool { + return false +} + +func (_ *BeegoInput) AcceptsXML() bool { + return false +} + +func (_ *BeegoInput) AcceptsYAML() bool { + return false +} + +func (_ *BeegoInput) Bind(_ interface{}, _ string) error { + return nil +} + +func (_ *BeegoInput) Cookie(_ string) string { + return "" +} + +func (_ *BeegoInput) CopyBody(_ int64) []byte { + return nil +} + +func (_ *BeegoInput) Data() map[interface{}]interface{} { + return nil +} + +func (_ *BeegoInput) Domain() string { + return "" +} + +func (_ *BeegoInput) GetData(_ interface{}) interface{} { + return nil +} + +func (_ *BeegoInput) Header(_ string) string { + return "" +} + +func (_ *BeegoInput) Host() string { + return "" +} + +func (_ *BeegoInput) IP() string { + return "" +} + +func (_ *BeegoInput) Is(_ string) bool { + return false +} + +func (_ *BeegoInput) IsAjax() bool { + return false +} + +func (_ *BeegoInput) IsDelete() bool { + return false +} + +func (_ *BeegoInput) IsGet() bool { + return false +} + +func (_ *BeegoInput) IsHead() bool { + return false +} + +func (_ *BeegoInput) IsOptions() bool { + return false +} + +func (_ *BeegoInput) IsPatch() bool { + return false +} + +func (_ *BeegoInput) IsPost() bool { + return false +} + +func (_ *BeegoInput) IsPut() bool { + return false +} + +func (_ *BeegoInput) IsSecure() bool { + return false +} + +func (_ *BeegoInput) IsUpload() bool { + return false +} + +func (_ *BeegoInput) IsWebsocket() bool { + return false +} + +func (_ *BeegoInput) Method() string { + return "" +} + +func (_ *BeegoInput) Param(_ string) string { + return "" +} + +func (_ *BeegoInput) Params() map[string]string { + return nil +} + +func (_ *BeegoInput) ParamsLen() int { + return 0 +} + +func (_ *BeegoInput) ParseFormOrMulitForm(_ int64) error { + return nil +} + +func (_ *BeegoInput) Port() int { + return 0 +} + +func (_ *BeegoInput) Protocol() string { + return "" +} + +func (_ *BeegoInput) Proxy() []string { + return nil +} + +func (_ *BeegoInput) Query(_ string) string { + return "" +} + +func (_ *BeegoInput) Refer() string { + return "" +} + +func (_ *BeegoInput) Referer() string { + return "" +} + +func (_ *BeegoInput) Reset(_ *Context) {} + +func (_ *BeegoInput) ResetParams() {} + +func (_ *BeegoInput) Scheme() string { + return "" +} + +func (_ *BeegoInput) Session(_ interface{}) interface{} { + return nil +} + +func (_ *BeegoInput) SetData(_ interface{}, _ interface{}) {} + +func (_ *BeegoInput) SetParam(_ string, _ string) {} + +func (_ *BeegoInput) Site() string { + return "" +} + +func (_ *BeegoInput) SubDomains() string { + return "" +} + +func (_ *BeegoInput) URI() string { + return "" +} + +func (_ *BeegoInput) URL() string { + return "" +} + +func (_ *BeegoInput) UserAgent() string { + return "" +} + +type BeegoOutput struct { + Context *Context + Status int + EnableGzip bool +} + +func (_ *BeegoOutput) Body(_ []byte) error { + return nil +} + +func (_ *BeegoOutput) ContentType(_ string) {} + +func (_ *BeegoOutput) Cookie(_ string, _ string, _ ...interface{}) {} + +func (_ *BeegoOutput) Download(_ string, _ ...string) {} + +func (_ *BeegoOutput) Header(_ string, _ string) {} + +func (_ *BeegoOutput) IsCachable() bool { + return false +} + +func (_ *BeegoOutput) IsClientError() bool { + return false +} + +func (_ *BeegoOutput) IsEmpty() bool { + return false +} + +func (_ *BeegoOutput) IsForbidden() bool { + return false +} + +func (_ *BeegoOutput) IsNotFound() bool { + return false +} + +func (_ *BeegoOutput) IsOk() bool { + return false +} + +func (_ *BeegoOutput) IsRedirect() bool { + return false +} + +func (_ *BeegoOutput) IsServerError() bool { + return false +} + +func (_ *BeegoOutput) IsSuccessful() bool { + return false +} + +func (_ *BeegoOutput) JSON(_ interface{}, _ bool, _ bool) error { + return nil +} + +func (_ *BeegoOutput) JSONP(_ interface{}, _ bool) error { + return nil +} + +func (_ *BeegoOutput) Reset(_ *Context) {} + +func (_ *BeegoOutput) ServeFormatted(_ interface{}, _ bool, _ ...bool) {} + +func (_ *BeegoOutput) Session(_ interface{}, _ interface{}) {} + +func (_ *BeegoOutput) SetStatus(_ int) {} + +func (_ *BeegoOutput) XML(_ interface{}, _ bool) error { + return nil +} + +func (_ *BeegoOutput) YAML(_ interface{}) error { + return nil +} + +type Context struct { + Input *BeegoInput + Output *BeegoOutput + Request *http.Request + ResponseWriter *Response +} + +func (_ *Context) Abort(_ int, _ string) {} + +func (_ *Context) CheckXSRFCookie() bool { + return false +} + +func (_ *Context) GetCookie(_ string) string { + return "" +} + +func (_ *Context) GetSecureCookie(_ string, _ string) (string, bool) { + return "", false +} + +func (_ *Context) Redirect(_ int, _ string) {} + +func (_ *Context) RenderMethodResult(_ interface{}) {} + +func (_ *Context) Reset(_ http.ResponseWriter, _ *http.Request) {} + +func (_ *Context) SetCookie(_ string, _ string, _ ...interface{}) {} + +func (_ *Context) SetSecureCookie(_ string, _ string, _ string, _ ...interface{}) {} + +func (_ *Context) WriteString(_ string) {} + +func (_ *Context) XSRFToken(_ string, _ int64) string { + return "" +} + +type Response struct { + ResponseWriter http.ResponseWriter + Started bool + Status int + Elapsed time.Duration +} + +func (_ Response) Header() http.Header { + return nil +} + +func (_ *Response) CloseNotify() <-chan bool { + return nil +} + +func (_ *Response) Flush() {} + +func (_ *Response) Hijack() (net.Conn, *bufio.ReadWriter, error) { + return nil, nil, nil +} + +func (_ *Response) Pusher() http.Pusher { + return nil +} + +func (_ *Response) Write(_ []byte) (int, error) { + return 0, nil +} + +func (_ *Response) WriteHeader(_ int) {} + +func WriteBody(_ string, _ io.Writer, _ []byte) (bool, string, error) { + return false, "", nil +} diff --git a/ql/test/library-tests/semmle/go/frameworks/Beego/vendor/github.com/astaxie/beego/logs/stub.go b/ql/test/library-tests/semmle/go/frameworks/Beego/vendor/github.com/astaxie/beego/logs/stub.go new file mode 100644 index 00000000000..5d019e64840 --- /dev/null +++ b/ql/test/library-tests/semmle/go/frameworks/Beego/vendor/github.com/astaxie/beego/logs/stub.go @@ -0,0 +1,94 @@ +// Code generated by depstubber. DO NOT EDIT. +// This is a simple stub for github.com/astaxie/beego/logs, strictly for use in testing. + +// See the LICENSE file for information about the licensing of the original library. +// Source: github.com/astaxie/beego/logs (exports: BeeLogger; functions: Alert,Critical,Debug,Emergency,Error,Info,Informational,Notice,Trace,Warn,Warning) + +// Package logs is a stub of github.com/astaxie/beego/logs, generated by depstubber. +package logs + +import () + +type BeeLogger struct{} + +func (_ *BeeLogger) Alert(_ string, _ ...interface{}) {} + +func (_ *BeeLogger) Async(_ ...int64) *BeeLogger { + return nil +} + +func (_ *BeeLogger) Close() {} + +func (_ *BeeLogger) Critical(_ string, _ ...interface{}) {} + +func (_ *BeeLogger) Debug(_ string, _ ...interface{}) {} + +func (_ *BeeLogger) DelLogger(_ string) error { + return nil +} + +func (_ *BeeLogger) Emergency(_ string, _ ...interface{}) {} + +func (_ *BeeLogger) EnableFuncCallDepth(_ bool) {} + +func (_ *BeeLogger) Error(_ string, _ ...interface{}) {} + +func (_ *BeeLogger) Flush() {} + +func (_ *BeeLogger) GetLevel() int { + return 0 +} + +func (_ *BeeLogger) GetLogFuncCallDepth() int { + return 0 +} + +func (_ *BeeLogger) Info(_ string, _ ...interface{}) {} + +func (_ *BeeLogger) Informational(_ string, _ ...interface{}) {} + +func (_ *BeeLogger) Notice(_ string, _ ...interface{}) {} + +func (_ *BeeLogger) Reset() {} + +func (_ *BeeLogger) SetLevel(_ int) {} + +func (_ *BeeLogger) SetLogFuncCallDepth(_ int) {} + +func (_ *BeeLogger) SetLogger(_ string, _ ...string) error { + return nil +} + +func (_ *BeeLogger) SetPrefix(_ string) {} + +func (_ *BeeLogger) Trace(_ string, _ ...interface{}) {} + +func (_ *BeeLogger) Warn(_ string, _ ...interface{}) {} + +func (_ *BeeLogger) Warning(_ string, _ ...interface{}) {} + +func (_ *BeeLogger) Write(_ []byte) (int, error) { + return 0, nil +} + +func Alert(_ interface{}, _ ...interface{}) {} + +func Critical(_ interface{}, _ ...interface{}) {} + +func Debug(_ interface{}, _ ...interface{}) {} + +func Emergency(_ interface{}, _ ...interface{}) {} + +func Error(_ interface{}, _ ...interface{}) {} + +func Info(_ interface{}, _ ...interface{}) {} + +func Informational(_ interface{}, _ ...interface{}) {} + +func Notice(_ interface{}, _ ...interface{}) {} + +func Trace(_ interface{}, _ ...interface{}) {} + +func Warn(_ interface{}, _ ...interface{}) {} + +func Warning(_ interface{}, _ ...interface{}) {} diff --git a/ql/test/library-tests/semmle/go/frameworks/Beego/vendor/github.com/astaxie/beego/stub.go b/ql/test/library-tests/semmle/go/frameworks/Beego/vendor/github.com/astaxie/beego/stub.go new file mode 100644 index 00000000000..e0ab719d833 --- /dev/null +++ b/ql/test/library-tests/semmle/go/frameworks/Beego/vendor/github.com/astaxie/beego/stub.go @@ -0,0 +1,369 @@ +// Code generated by depstubber. DO NOT EDIT. +// This is a simple stub for github.com/astaxie/beego, strictly for use in testing. + +// See the LICENSE file for information about the licensing of the original library. +// Source: github.com/astaxie/beego (exports: App,Controller; functions: Alert,Critical,Debug,Emergency,Error,HTML2str,Htmlquote,Htmlunquote,Info,Informational,MapGet,Notice,ParseForm,Str2html,Substr,Trace,Walk,Warn,Warning) + +// Package beego is a stub of github.com/astaxie/beego, generated by depstubber. +package beego + +import ( + context "github.com/astaxie/beego/context" + template "html/template" + multipart "mime/multipart" + http "net/http" + url "net/url" + filepath "path/filepath" +) + +type App struct { + Handlers *ControllerRegister + Server *http.Server +} + +func (_ *App) Run(_ ...MiddleWare) {} + +type Controller struct { + Ctx interface{} + Data map[interface{}]interface{} + AppController interface{} + TplName string + ViewPath string + Layout string + LayoutSections map[string]string + TplPrefix string + TplExt string + EnableRender bool + XSRFExpire int + EnableXSRF bool + CruSession interface{} +} + +func (_ *Controller) Abort(_ string) {} + +func (_ *Controller) CheckXSRFCookie() bool { + return false +} + +func (_ *Controller) CustomAbort(_ int, _ string) {} + +func (_ *Controller) DelSession(_ interface{}) {} + +func (_ *Controller) Delete() {} + +func (_ *Controller) DestroySession() {} + +func (_ *Controller) Finish() {} + +func (_ *Controller) Get() {} + +func (_ *Controller) GetBool(_ string, _ ...bool) (bool, error) { + return false, nil +} + +func (_ *Controller) GetControllerAndAction() (string, string) { + return "", "" +} + +func (_ *Controller) GetFile(_ string) (multipart.File, *multipart.FileHeader, error) { + return nil, nil, nil +} + +func (_ *Controller) GetFiles(_ string) ([]*multipart.FileHeader, error) { + return nil, nil +} + +func (_ *Controller) GetFloat(_ string, _ ...float64) (float64, error) { + return 0, nil +} + +func (_ *Controller) GetInt(_ string, _ ...int) (int, error) { + return 0, nil +} + +func (_ *Controller) GetInt16(_ string, _ ...int16) (int16, error) { + return 0, nil +} + +func (_ *Controller) GetInt32(_ string, _ ...int32) (int32, error) { + return 0, nil +} + +func (_ *Controller) GetInt64(_ string, _ ...int64) (int64, error) { + return 0, nil +} + +func (_ *Controller) GetInt8(_ string, _ ...int8) (int8, error) { + return 0, nil +} + +func (_ *Controller) GetSecureCookie(_ string, _ string) (string, bool) { + return "", false +} + +func (_ *Controller) GetSession(_ interface{}) interface{} { + return nil +} + +func (_ *Controller) GetString(_ string, _ ...string) string { + return "" +} + +func (_ *Controller) GetStrings(_ string, _ ...[]string) []string { + return nil +} + +func (_ *Controller) GetUint16(_ string, _ ...uint16) (uint16, error) { + return 0, nil +} + +func (_ *Controller) GetUint32(_ string, _ ...uint32) (uint32, error) { + return 0, nil +} + +func (_ *Controller) GetUint64(_ string, _ ...uint64) (uint64, error) { + return 0, nil +} + +func (_ *Controller) GetUint8(_ string, _ ...byte) (byte, error) { + return 0, nil +} + +func (_ *Controller) HandlerFunc(_ string) bool { + return false +} + +func (_ *Controller) Head() {} + +func (_ *Controller) Init(_ interface{}, _ string, _ string, _ interface{}) {} + +func (_ *Controller) Input() url.Values { + return nil +} + +func (_ *Controller) IsAjax() bool { + return false +} + +func (_ *Controller) Mapping(_ string, _ func()) {} + +func (_ *Controller) Options() {} + +func (_ *Controller) ParseForm(_ interface{}) error { + return nil +} + +func (_ *Controller) Patch() {} + +func (_ *Controller) Post() {} + +func (_ *Controller) Prepare() {} + +func (_ *Controller) Put() {} + +func (_ *Controller) Redirect(_ string, _ int) {} + +func (_ *Controller) Render() error { + return nil +} + +func (_ *Controller) RenderBytes() ([]byte, error) { + return nil, nil +} + +func (_ *Controller) RenderString() (string, error) { + return "", nil +} + +func (_ *Controller) SaveToFile(_ string, _ string) error { + return nil +} + +func (_ *Controller) ServeFormatted(_ ...bool) {} + +func (_ *Controller) ServeJSON(_ ...bool) {} + +func (_ *Controller) ServeJSONP() {} + +func (_ *Controller) ServeXML() {} + +func (_ *Controller) ServeYAML() {} + +func (_ *Controller) SessionRegenerateID() {} + +func (_ *Controller) SetData(_ interface{}) {} + +func (_ *Controller) SetSecureCookie(_ string, _ string, _ string, _ ...interface{}) {} + +func (_ *Controller) SetSession(_ interface{}, _ interface{}) {} + +func (_ *Controller) StartSession() interface{} { + return nil +} + +func (_ *Controller) StopRun() {} + +func (_ *Controller) Trace() {} + +func (_ *Controller) URLFor(_ string, _ ...interface{}) string { + return "" +} + +func (_ *Controller) URLMapping() {} + +func (_ *Controller) XSRFFormHTML() string { + return "" +} + +func (_ *Controller) XSRFToken() string { + return "" +} + +type ControllerInfo struct{} + +func (_ *ControllerInfo) GetPattern() string { + return "" +} + +type ControllerInterface interface { + CheckXSRFCookie() bool + Delete() + Finish() + Get() + HandlerFunc(_ string) bool + Head() + Init(_ interface{}, _ string, _ string, _ interface{}) + Options() + Patch() + Post() + Prepare() + Put() + Render() error + Trace() + URLMapping() + XSRFToken() string +} + +type ControllerRegister struct{} + +func (_ *ControllerRegister) Add(_ string, _ ControllerInterface, _ ...string) {} + +func (_ *ControllerRegister) AddAuto(_ ControllerInterface) {} + +func (_ *ControllerRegister) AddAutoPrefix(_ string, _ ControllerInterface) {} + +func (_ *ControllerRegister) AddMethod(_ string, _ string, _ FilterFunc) {} + +func (_ *ControllerRegister) Any(_ string, _ FilterFunc) {} + +func (_ *ControllerRegister) Delete(_ string, _ FilterFunc) {} + +func (_ *ControllerRegister) FindPolicy(_ interface{}) []PolicyFunc { + return nil +} + +func (_ *ControllerRegister) FindRouter(_ interface{}) (*ControllerInfo, bool) { + return nil, false +} + +func (_ *ControllerRegister) Get(_ string, _ FilterFunc) {} + +func (_ *ControllerRegister) GetContext() interface{} { + return nil +} + +func (_ *ControllerRegister) GiveBackContext(_ interface{}) {} + +func (_ *ControllerRegister) Handler(_ string, _ http.Handler, _ ...interface{}) {} + +func (_ *ControllerRegister) Head(_ string, _ FilterFunc) {} + +func (_ *ControllerRegister) Include(_ ...ControllerInterface) {} + +func (_ *ControllerRegister) InsertFilter(_ string, _ int, _ FilterFunc, _ ...bool) error { + return nil +} + +func (_ *ControllerRegister) Options(_ string, _ FilterFunc) {} + +func (_ *ControllerRegister) Patch(_ string, _ FilterFunc) {} + +func (_ *ControllerRegister) Post(_ string, _ FilterFunc) {} + +func (_ *ControllerRegister) Put(_ string, _ FilterFunc) {} + +func (_ *ControllerRegister) ServeHTTP(_ http.ResponseWriter, _ *http.Request) {} + +func (_ *ControllerRegister) URLFor(_ string, _ ...interface{}) string { + return "" +} + +func Alert(_ ...interface{}) {} + +func Critical(_ ...interface{}) {} + +func Debug(_ ...interface{}) {} + +func Emergency(_ ...interface{}) {} + +func Error(_ ...interface{}) {} + +type FilterFunc func(*context.Context) + +func HTML2str(_ string) string { + return "" +} + +func Htmlquote(_ string) string { + return "" +} + +func Htmlunquote(_ string) string { + return "" +} + +func Info(_ ...interface{}) {} + +func Informational(_ ...interface{}) {} + +func MapGet(_ interface{}, _ ...interface{}) (interface{}, error) { + return nil, nil +} + +type MiddleWare func(http.Handler) http.Handler + +func Notice(_ ...interface{}) {} + +func ParseForm(_ url.Values, _ interface{}) error { + return nil +} + +type PolicyFunc func(interface{}) + +func Post(rootpath string, f FilterFunc) *App { + return nil +} + +func Str2html(_ string) template.HTML { + return "" +} + +func Substr(_ string, _ int, _ int) string { + return "" +} + +func Trace(_ ...interface{}) {} + +func Walk(_ http.FileSystem, _ string, _ filepath.WalkFunc) error { + return nil +} + +func Warn(_ ...interface{}) {} + +func Warning(_ ...interface{}) {} + +type FileSystem struct{} + +func (_ FileSystem) Open(_ string) (http.File, error) { + return nil, nil +} diff --git a/ql/test/library-tests/semmle/go/frameworks/Beego/vendor/github.com/astaxie/beego/utils/stub.go b/ql/test/library-tests/semmle/go/frameworks/Beego/vendor/github.com/astaxie/beego/utils/stub.go new file mode 100644 index 00000000000..0ea348a30bd --- /dev/null +++ b/ql/test/library-tests/semmle/go/frameworks/Beego/vendor/github.com/astaxie/beego/utils/stub.go @@ -0,0 +1,130 @@ +// Code generated by depstubber. DO NOT EDIT. +// This is a simple stub for github.com/astaxie/beego/utils, strictly for use in testing. + +// See the LICENSE file for information about the licensing of the original library. +// Source: github.com/astaxie/beego/utils (exports: BeeMap,Email; functions: Display,GetDisplayString,SliceChunk,SliceDiff,SliceFilter,SliceIntersect,SliceMerge,SlicePad,SliceRand,SliceReduce,SliceShuffle,SliceUnique) + +// Package utils is a stub of github.com/astaxie/beego/utils, generated by depstubber. +package utils + +import ( + io "io" + smtp "net/smtp" + textproto "net/textproto" +) + +type Attachment struct { + Filename string + Header textproto.MIMEHeader + Content []byte +} + +type BeeMap struct{} + +func NewBeeMap() *BeeMap { + return nil +} + +func (_ *BeeMap) Check(_ interface{}) bool { + return false +} + +func (_ *BeeMap) Count() int { + return 0 +} + +func (_ *BeeMap) Delete(_ interface{}) {} + +func (_ *BeeMap) Get(_ interface{}) interface{} { + return nil +} + +func (_ *BeeMap) Items() map[interface{}]interface{} { + return nil +} + +func (_ *BeeMap) Set(_ interface{}, _ interface{}) bool { + return false +} + +type Email struct { + Auth smtp.Auth + Identity string + Username string + Password string + Host string + Port int + From string + To []string + Bcc []string + Cc []string + Subject string + Text string + HTML string + Headers textproto.MIMEHeader + Attachments []*Attachment + ReadReceipt []string +} + +func (_ *Email) Attach(_ io.Reader, _ string, _ ...string) (*Attachment, error) { + return nil, nil +} + +func (_ *Email) AttachFile(_ ...string) (*Attachment, error) { + return nil, nil +} + +func (_ *Email) Bytes() ([]byte, error) { + return nil, nil +} + +func (_ *Email) Send() error { + return nil +} + +func Display(_ ...interface{}) { +} + +func GetDisplayString(_ ...interface{}) string { + return "" +} + +func SliceChunk(_ []interface{}, _ int) [][]interface{} { + return nil +} + +func SliceDiff(_ []interface{}, _ []interface{}) []interface{} { + return nil +} + +func SliceFilter(_ []interface{}, _ interface{}) []interface{} { + return nil +} + +func SliceIntersect(_ []interface{}, _ []interface{}) []interface{} { + return nil +} + +func SliceMerge(_ []interface{}, _ []interface{}) []interface{} { + return nil +} + +func SlicePad(_ []interface{}, _ int, _ interface{}) []interface{} { + return nil +} + +func SliceRand(_ []interface{}) interface{} { + return nil +} + +func SliceReduce(_ []interface{}, _ interface{}) []interface{} { + return nil +} + +func SliceShuffle(_ []interface{}) []interface{} { + return nil +} + +func SliceUnique(_ []interface{}) []interface{} { + return nil +} diff --git a/ql/test/library-tests/semmle/go/frameworks/Beego/vendor/modules.txt b/ql/test/library-tests/semmle/go/frameworks/Beego/vendor/modules.txt new file mode 100644 index 00000000000..864abfe6c70 --- /dev/null +++ b/ql/test/library-tests/semmle/go/frameworks/Beego/vendor/modules.txt @@ -0,0 +1,3 @@ +# github.com/astaxie/beego v1.12.3 +## explicit +github.com/astaxie/beego