diff --git a/ql/src/experimental/frameworks/Fiber.json b/ql/src/experimental/frameworks/Fiber.json new file mode 100644 index 00000000000..30549353dc1 --- /dev/null +++ b/ql/src/experimental/frameworks/Fiber.json @@ -0,0 +1,1027 @@ +{ + "Name": "Fiber", + "Preload": null, + "Models": [ + { + "Name": "TaintTracking", + "Kind": "TaintTracking", + "Methods": [ + { + "Name": "Self", + "Selectors": [ + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/fiber", + "Version": "v1.14.6", + "ID": "Function-NewError", + "Pos": null, + "Flows": { + "Blocks": [ + { + "Inp": [ + false, + true, + false + ], + "Out": [ + false, + false, + true + ] + } + ], + "Enabled": true + }, + "Name": "NewError" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/utils", + "Version": "v0.1.0", + "ID": "Function-GetBytes", + "Pos": null, + "Flows": { + "Blocks": [ + { + "Inp": [ + true, + false + ], + "Out": [ + false, + true + ] + } + ], + "Enabled": true + }, + "Name": "GetBytes" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/utils", + "Version": "v0.1.0", + "ID": "Function-GetString", + "Pos": null, + "Flows": { + "Blocks": [ + { + "Inp": [ + true, + false + ], + "Out": [ + false, + true + ] + } + ], + "Enabled": true + }, + "Name": "GetString" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/utils", + "Version": "v0.1.0", + "ID": "Function-ImmutableString", + "Pos": null, + "Flows": { + "Blocks": [ + { + "Inp": [ + true, + false + ], + "Out": [ + false, + true + ] + } + ], + "Enabled": true + }, + "Name": "ImmutableString" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/utils", + "Version": "v0.1.0", + "ID": "Function-SafeBytes", + "Pos": null, + "Flows": { + "Blocks": [ + { + "Inp": [ + true, + false + ], + "Out": [ + false, + true + ] + } + ], + "Enabled": true + }, + "Name": "SafeBytes" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/utils", + "Version": "v0.1.0", + "ID": "Function-SafeString", + "Pos": null, + "Flows": { + "Blocks": [ + { + "Inp": [ + true, + false + ], + "Out": [ + false, + true + ] + } + ], + "Enabled": true + }, + "Name": "SafeString" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/utils", + "Version": "v0.1.0", + "ID": "Function-ToLower", + "Pos": null, + "Flows": { + "Blocks": [ + { + "Inp": [ + true, + false + ], + "Out": [ + false, + true + ] + } + ], + "Enabled": true + }, + "Name": "ToLower" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/utils", + "Version": "v0.1.0", + "ID": "Function-ToLowerBytes", + "Pos": null, + "Flows": { + "Blocks": [ + { + "Inp": [ + true, + false + ], + "Out": [ + false, + true + ] + } + ], + "Enabled": true + }, + "Name": "ToLowerBytes" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/utils", + "Version": "v0.1.0", + "ID": "Function-ToUpper", + "Pos": null, + "Flows": { + "Blocks": [ + { + "Inp": [ + true, + false + ], + "Out": [ + false, + true + ] + } + ], + "Enabled": true + }, + "Name": "ToUpper" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/utils", + "Version": "v0.1.0", + "ID": "Function-ToUpperBytes", + "Pos": null, + "Flows": { + "Blocks": [ + { + "Inp": [ + true, + false + ], + "Out": [ + false, + true + ] + } + ], + "Enabled": true + }, + "Name": "ToUpperBytes" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/utils", + "Version": "v0.1.0", + "ID": "Function-Trim", + "Pos": null, + "Flows": { + "Blocks": [ + { + "Inp": [ + true, + false, + false + ], + "Out": [ + false, + false, + true + ] + } + ], + "Enabled": true + }, + "Name": "Trim" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/utils", + "Version": "v0.1.0", + "ID": "Function-TrimBytes", + "Pos": null, + "Flows": { + "Blocks": [ + { + "Inp": [ + true, + false, + false + ], + "Out": [ + false, + false, + true + ] + } + ], + "Enabled": true + }, + "Name": "TrimBytes" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/utils", + "Version": "v0.1.0", + "ID": "Function-TrimLeft", + "Pos": null, + "Flows": { + "Blocks": [ + { + "Inp": [ + true, + false, + false + ], + "Out": [ + false, + false, + true + ] + } + ], + "Enabled": true + }, + "Name": "TrimLeft" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/utils", + "Version": "v0.1.0", + "ID": "Function-TrimLeftBytes", + "Pos": null, + "Flows": { + "Blocks": [ + { + "Inp": [ + true, + false, + false + ], + "Out": [ + false, + false, + true + ] + } + ], + "Enabled": true + }, + "Name": "TrimLeftBytes" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/utils", + "Version": "v0.1.0", + "ID": "Function-TrimRight", + "Pos": null, + "Flows": { + "Blocks": [ + { + "Inp": [ + true, + false, + false + ], + "Out": [ + false, + false, + true + ] + } + ], + "Enabled": true + }, + "Name": "TrimRight" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/utils", + "Version": "v0.1.0", + "ID": "Function-TrimRightBytes", + "Pos": null, + "Flows": { + "Blocks": [ + { + "Inp": [ + true, + false, + false + ], + "Out": [ + false, + false, + true + ] + } + ], + "Enabled": true + }, + "Name": "TrimRightBytes" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/utils", + "Version": "v0.1.0", + "ID": "Function-UnsafeBytes", + "Pos": null, + "Flows": { + "Blocks": [ + { + "Inp": [ + true, + false + ], + "Out": [ + false, + true + ] + } + ], + "Enabled": true + }, + "Name": "UnsafeBytes" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/utils", + "Version": "v0.1.0", + "ID": "Function-UnsafeString", + "Pos": null, + "Flows": { + "Blocks": [ + { + "Inp": [ + true, + false + ], + "Out": [ + false, + true + ] + } + ], + "Enabled": true + }, + "Name": "UnsafeString" + } + } + ] + } + ] + }, + { + "Name": "Redirect", + "Kind": "HTTP::Redirect", + "Methods": [ + { + "Name": "{url:Param} \u003c- $url", + "Selectors": [ + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/fiber", + "Version": "v1.14.6", + "ID": "TypeMethod-Ctx-Redirect", + "Pos": [ + false, + true, + false + ], + "Flows": null, + "Name": "Redirect" + } + } + ] + } + ] + }, + { + "Name": "HeaderWrite", + "Kind": "HTTP::HeaderWrite", + "Methods": [ + { + "Name": "{key:Param, val:Param} \u003c- $key", + "Selectors": [ + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/fiber", + "Version": "v1.14.6", + "ID": "TypeMethod-Ctx-Append", + "Pos": [ + false, + true, + false + ], + "Flows": null, + "Name": "Append" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/fiber", + "Version": "v1.14.6", + "ID": "TypeMethod-Ctx-Set", + "Pos": [ + false, + true, + false + ], + "Flows": null, + "Name": "Set" + } + } + ] + }, + { + "Name": "{key:Param, val:Param} \u003c- $val", + "Selectors": [ + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/fiber", + "Version": "v1.14.6", + "ID": "TypeMethod-Ctx-Append", + "Pos": [ + false, + false, + true + ], + "Flows": null, + "Name": "Append" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/fiber", + "Version": "v1.14.6", + "ID": "TypeMethod-Ctx-Set", + "Pos": [ + false, + false, + true + ], + "Flows": null, + "Name": "Set" + } + } + ] + }, + { + "Name": "{ct:Param} \u003c- $ct", + "Selectors": [] + }, + { + "Name": "{ct:Inferred} \u003c- *", + "Selectors": [] + } + ] + }, + { + "Name": "ResponseBody", + "Kind": "HTTP::ResponseBody", + "Methods": [ + { + "Name": "{ct:Inferred, body:Param} \u003c- $body", + "Selectors": [ + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/fiber", + "Version": "v1.14.6", + "ID": "TypeMethod-Ctx-JSON", + "Pos": [ + false, + true, + false + ], + "Flows": null, + "Name": "JSON" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/fiber", + "Version": "v1.14.6", + "ID": "TypeMethod-Ctx-JSONP", + "Pos": [ + false, + true, + false, + false + ], + "Flows": null, + "Name": "JSONP" + } + } + ] + }, + { + "Name": "{ct:Param, body:Param} \u003c- $body", + "Selectors": [] + }, + { + "Name": "{ct:Param, body:Param} \u003c- $ct", + "Selectors": [] + }, + { + "Name": "{body:Param} \u003c- $body", + "Selectors": [ + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/fiber", + "Version": "v1.14.6", + "ID": "TypeMethod-Ctx-Format", + "Pos": [ + false, + true + ], + "Flows": null, + "Name": "Format" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/fiber", + "Version": "v1.14.6", + "ID": "TypeMethod-Ctx-Send", + "Pos": [ + false, + true + ], + "Flows": null, + "Name": "Send" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/fiber", + "Version": "v1.14.6", + "ID": "TypeMethod-Ctx-SendBytes", + "Pos": [ + false, + true + ], + "Flows": null, + "Name": "SendBytes" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/fiber", + "Version": "v1.14.6", + "ID": "TypeMethod-Ctx-SendStream", + "Pos": [ + false, + true, + false + ], + "Flows": null, + "Name": "SendStream" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/fiber", + "Version": "v1.14.6", + "ID": "TypeMethod-Ctx-SendString", + "Pos": [ + false, + true + ], + "Flows": null, + "Name": "SendString" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/fiber", + "Version": "v1.14.6", + "ID": "TypeMethod-Ctx-Write", + "Pos": [ + false, + true + ], + "Flows": null, + "Name": "Write" + } + } + ] + } + ] + }, + { + "Name": "UntrustedFlowSources", + "Kind": "UntrustedFlowSource", + "Methods": [ + { + "Name": "{source:[](Param|Result|Fields|Type)} \u003c- $source", + "Selectors": [ + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/fiber", + "Version": "v1.14.6", + "ID": "TypeMethod-Ctx-BaseURL", + "Pos": [ + false, + true + ], + "Flows": null, + "Name": "BaseURL" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/fiber", + "Version": "v1.14.6", + "ID": "TypeMethod-Ctx-Body", + "Pos": [ + false, + true + ], + "Flows": null, + "Name": "Body" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/fiber", + "Version": "v1.14.6", + "ID": "TypeMethod-Ctx-BodyParser", + "Pos": [ + false, + true, + false + ], + "Flows": null, + "Name": "BodyParser" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/fiber", + "Version": "v1.14.6", + "ID": "TypeMethod-Ctx-Cookies", + "Pos": [ + false, + false, + false, + true + ], + "Flows": null, + "Name": "Cookies" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/fiber", + "Version": "v1.14.6", + "ID": "TypeMethod-Ctx-FormFile", + "Pos": [ + false, + false, + true, + false + ], + "Flows": null, + "Name": "FormFile" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/fiber", + "Version": "v1.14.6", + "ID": "TypeMethod-Ctx-FormValue", + "Pos": [ + false, + false, + true + ], + "Flows": null, + "Name": "FormValue" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/fiber", + "Version": "v1.14.6", + "ID": "TypeMethod-Ctx-Get", + "Pos": [ + false, + false, + false, + true + ], + "Flows": null, + "Name": "Get" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/fiber", + "Version": "v1.14.6", + "ID": "TypeMethod-Ctx-Hostname", + "Pos": [ + false, + true + ], + "Flows": null, + "Name": "Hostname" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/fiber", + "Version": "v1.14.6", + "ID": "TypeMethod-Ctx-Method", + "Pos": [ + false, + false, + true + ], + "Flows": null, + "Name": "Method" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/fiber", + "Version": "v1.14.6", + "ID": "TypeMethod-Ctx-MultipartForm", + "Pos": [ + false, + true, + false + ], + "Flows": null, + "Name": "MultipartForm" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/fiber", + "Version": "v1.14.6", + "ID": "TypeMethod-Ctx-OriginalURL", + "Pos": [ + false, + true + ], + "Flows": null, + "Name": "OriginalURL" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/fiber", + "Version": "v1.14.6", + "ID": "TypeMethod-Ctx-Params", + "Pos": [ + false, + false, + false, + true + ], + "Flows": null, + "Name": "Params" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/fiber", + "Version": "v1.14.6", + "ID": "TypeMethod-Ctx-Path", + "Pos": [ + false, + false, + true + ], + "Flows": null, + "Name": "Path" + } + }, + { + "Kind": "Struct", + "Qualifier": { + "Path": "github.com/gofiber/fiber", + "Version": "v1.14.6", + "ID": "Struct-Error", + "TypeName": "Error", + "Fields": { + "Message": null + } + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/fiber", + "Version": "v1.14.6", + "ID": "TypeMethod-Ctx-Query", + "Pos": [ + false, + false, + false, + true + ], + "Flows": null, + "Name": "Query" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/fiber", + "Version": "v1.14.6", + "ID": "TypeMethod-Ctx-QueryParser", + "Pos": [ + false, + true, + false + ], + "Flows": null, + "Name": "QueryParser" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/fiber", + "Version": "v1.14.6", + "ID": "TypeMethod-Ctx-Range", + "Pos": [ + false, + false, + true, + false + ], + "Flows": null, + "Name": "Range" + } + }, + { + "Kind": "Func", + "Qualifier": { + "Path": "github.com/gofiber/fiber", + "Version": "v1.14.6", + "ID": "TypeMethod-Ctx-Subdomains", + "Pos": [ + false, + false, + true + ], + "Flows": null, + "Name": "Subdomains" + } + }, + { + "Kind": "Struct", + "Qualifier": { + "Path": "github.com/gofiber/fiber", + "Version": "v1.14.6", + "ID": "Struct-Cookie", + "TypeName": "Cookie", + "Fields": { + "Domain": null, + "Name": null, + "Path": null, + "SameSite": null, + "Value": null + } + } + } + ] + } + ] + } + ] +} diff --git a/ql/src/experimental/frameworks/Fiber.qll b/ql/src/experimental/frameworks/Fiber.qll new file mode 100644 index 00000000000..08a0d961d41 --- /dev/null +++ b/ql/src/experimental/frameworks/Fiber.qll @@ -0,0 +1,400 @@ +/** + * Provides classes for working with concepts from the following packages: + * - [`github.com/gofiber/fiber@v1.14.6`](https://pkg.go.dev/github.com/gofiber/fiber@v1.14.6) + * - [`github.com/gofiber/utils@v0.1.0`](https://pkg.go.dev/github.com/gofiber/utils@v0.1.0) + * + * Generated with `Fiber.json` spec. + */ + +import go + +/** + * Provides classes for working with concepts from the following packages: + * - [`github.com/gofiber/fiber@v1.14.6`](https://pkg.go.dev/github.com/gofiber/fiber@v1.14.6) + * - [`github.com/gofiber/utils@v0.1.0`](https://pkg.go.dev/github.com/gofiber/utils@v0.1.0) + */ +private module Fiber { + string fiberPackagePath() { result = package("github.com/gofiber/fiber", "") } + + string utilsPackagePath() { result = package("github.com/gofiber/utils", "") } + + /** + * Models taint-tracking through functions. + */ + private class TaintTrackingFunctionModels extends TaintTracking::FunctionModel { + FunctionInput inp; + FunctionOutput out; + + TaintTrackingFunctionModels() { + // Taint-tracking models for package: github.com/gofiber/fiber@v1.14.6 + // signature: func NewError(code int, message ...string) *Error + this.hasQualifiedName(fiberPackagePath(), "NewError") and + inp.isParameter(any(int i | i >= 1)) and + out.isResult() + or + // Taint-tracking models for package: github.com/gofiber/utils@v0.1.0 + ( + // signature: func GetBytes(s string) []byte + this.hasQualifiedName(utilsPackagePath(), "GetBytes") and + inp.isParameter(0) and + out.isResult() + or + // signature: func GetString(b []byte) string + this.hasQualifiedName(utilsPackagePath(), "GetString") and + inp.isParameter(0) and + out.isResult() + or + // signature: func ImmutableString(s string) string + this.hasQualifiedName(utilsPackagePath(), "ImmutableString") and + inp.isParameter(0) and + out.isResult() + or + // signature: func SafeBytes(b []byte) []byte + this.hasQualifiedName(utilsPackagePath(), "SafeBytes") and + inp.isParameter(0) and + out.isResult() + or + // signature: func SafeString(s string) string + this.hasQualifiedName(utilsPackagePath(), "SafeString") and + inp.isParameter(0) and + out.isResult() + or + // signature: func ToLower(b string) string + this.hasQualifiedName(utilsPackagePath(), "ToLower") and + inp.isParameter(0) and + out.isResult() + or + // signature: func ToLowerBytes(b []byte) []byte + this.hasQualifiedName(utilsPackagePath(), "ToLowerBytes") and + inp.isParameter(0) and + out.isResult() + or + // signature: func ToUpper(b string) string + this.hasQualifiedName(utilsPackagePath(), "ToUpper") and + inp.isParameter(0) and + out.isResult() + or + // signature: func ToUpperBytes(b []byte) []byte + this.hasQualifiedName(utilsPackagePath(), "ToUpperBytes") and + inp.isParameter(0) and + out.isResult() + or + // signature: func Trim(s string, cutset byte) string + this.hasQualifiedName(utilsPackagePath(), "Trim") and + inp.isParameter(0) and + out.isResult() + or + // signature: func TrimBytes(b []byte, cutset byte) []byte + this.hasQualifiedName(utilsPackagePath(), "TrimBytes") and + inp.isParameter(0) and + out.isResult() + or + // signature: func TrimLeft(s string, cutset byte) string + this.hasQualifiedName(utilsPackagePath(), "TrimLeft") and + inp.isParameter(0) and + out.isResult() + or + // signature: func TrimLeftBytes(b []byte, cutset byte) []byte + this.hasQualifiedName(utilsPackagePath(), "TrimLeftBytes") and + inp.isParameter(0) and + out.isResult() + or + // signature: func TrimRight(s string, cutset byte) string + this.hasQualifiedName(utilsPackagePath(), "TrimRight") and + inp.isParameter(0) and + out.isResult() + or + // signature: func TrimRightBytes(b []byte, cutset byte) []byte + this.hasQualifiedName(utilsPackagePath(), "TrimRightBytes") and + inp.isParameter(0) and + out.isResult() + or + // signature: func UnsafeBytes(s string) (bs []byte) + this.hasQualifiedName(utilsPackagePath(), "UnsafeBytes") and + inp.isParameter(0) and + out.isResult() + or + // signature: func UnsafeString(b []byte) string + this.hasQualifiedName(utilsPackagePath(), "UnsafeString") and + inp.isParameter(0) and + out.isResult() + ) + } + + override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) { + input = inp and output = out + } + } + + /** + * Models HTTP redirects. + */ + private class Redirect extends HTTP::Redirect::Range, DataFlow::CallNode { + string package; + DataFlow::Node urlNode; + + Redirect() { + // HTTP redirect models for package: github.com/gofiber/fiber@v1.14.6 + package = fiberPackagePath() and + // Receiver type: Ctx + ( + // signature: func (*Ctx).Redirect(location string, status ...int) + this = any(Method m | m.hasQualifiedName(package, "Ctx", "Redirect")).getACall() and + urlNode = this.getArgument(0) + ) + } + + override DataFlow::Node getUrl() { result = urlNode } + + override HTTP::ResponseWriter getResponseWriter() { result.getANode() = this.getReceiver() } + } + + /** + * Models HTTP header writers. + * The write is done with a call where you can set both the key and the value of the header. + */ + private class HeaderWrite extends HTTP::HeaderWrite::Range, DataFlow::CallNode { + DataFlow::Node receiverNode; + DataFlow::Node headerNameNode; + DataFlow::Node headerValueNode; + + HeaderWrite() { + setsHeaderDynamicKeyValue(_, _, this, headerNameNode, headerValueNode, receiverNode) + } + + override DataFlow::Node getName() { result = headerNameNode } + + override DataFlow::Node getValue() { result = headerValueNode } + + override HTTP::ResponseWriter getResponseWriter() { result.getANode() = receiverNode } + } + + // Holds for a call that sets a header with a key-value combination. + private predicate setsHeaderDynamicKeyValue( + string package, string receiverName, DataFlow::CallNode headerSetterCall, + DataFlow::Node headerNameNode, DataFlow::Node headerValueNode, DataFlow::Node receiverNode + ) { + exists(string methodName, Method met | + met.hasQualifiedName(package, receiverName, methodName) and + headerSetterCall = met.getACall() and + receiverNode = headerSetterCall.getReceiver() + | + package = fiberPackagePath() and + ( + // Receiver type: Ctx + receiverName = "Ctx" and + ( + // signature: func (*Ctx).Append(field string, values ...string) + methodName = "Append" and + headerNameNode = headerSetterCall.getArgument(0) and + headerValueNode = headerSetterCall.getArgument(any(int i | i >= 1)) + or + // signature: func (*Ctx).Set(key string, val string) + methodName = "Set" and + headerNameNode = headerSetterCall.getArgument(0) and + headerValueNode = headerSetterCall.getArgument(1) + ) + ) + ) + } + + /** + * Models HTTP ResponseBody where the content-type is static and non-modifiable. + */ + private class ResponseBodyStaticContentType extends HTTP::ResponseBody::Range { + string contentTypeString; + DataFlow::Node receiverNode; + + ResponseBodyStaticContentType() { + exists(string package, string receiverName | + setsBodyAndStaticContentType(package, receiverName, this, contentTypeString, receiverNode) + ) + } + + override string getAContentType() { result = contentTypeString } + + override HTTP::ResponseWriter getResponseWriter() { result.getANode() = receiverNode } + } + + // Holds for a call that sets the body; the content-type is implicitly set. + private predicate setsBodyAndStaticContentType( + string package, string receiverName, DataFlow::Node bodyNode, string contentTypeString, + DataFlow::Node receiverNode + ) { + exists(string methodName, Method met, DataFlow::CallNode bodySetterCall | + met.hasQualifiedName(package, receiverName, methodName) and + bodySetterCall = met.getACall() and + receiverNode = bodySetterCall.getReceiver() + | + package = fiberPackagePath() and + ( + // Receiver type: Ctx + receiverName = "Ctx" and + ( + // signature: func (*Ctx).JSON(data interface{}) error + methodName = "JSON" and + bodyNode = bodySetterCall.getArgument(0) and + contentTypeString = "application/json" + or + // signature: func (*Ctx).JSONP(data interface{}, callback ...string) error + methodName = "JSONP" and + bodyNode = bodySetterCall.getArgument(0) and + contentTypeString = "application/javascript" + ) + ) + ) + } + + /** + * Models HTTP ResponseBody where only the body is set. + */ + private class ResponseBodyNoContentType extends HTTP::ResponseBody::Range { + DataFlow::Node receiverNode; + + ResponseBodyNoContentType() { + exists(string package, string receiverName | + setsBody(package, receiverName, receiverNode, this) + ) + } + + override HTTP::ResponseWriter getResponseWriter() { result.getANode() = receiverNode } + } + + // Holds for a call that sets the body. The content-type is not defined. + private predicate setsBody( + string package, string receiverName, DataFlow::Node receiverNode, DataFlow::Node bodyNode + ) { + exists(string methodName, Method met, DataFlow::CallNode bodySetterCall | + met.hasQualifiedName(package, receiverName, methodName) and + bodySetterCall = met.getACall() and + receiverNode = bodySetterCall.getReceiver() + | + package = fiberPackagePath() and + ( + // Receiver type: Ctx + receiverName = "Ctx" and + ( + // signature: func (*Ctx).Format(body interface{}) + methodName = "Format" and + bodyNode = bodySetterCall.getArgument(0) + or + // signature: func (*Ctx).Send(bodies ...interface{}) + methodName = "Send" and + bodyNode = bodySetterCall.getArgument(_) + or + // signature: func (*Ctx).SendBytes(body []byte) + methodName = "SendBytes" and + bodyNode = bodySetterCall.getArgument(0) + or + // signature: func (*Ctx).SendStream(stream io.Reader, size ...int) + methodName = "SendStream" and + bodyNode = bodySetterCall.getArgument(0) + or + // signature: func (*Ctx).SendString(body string) + methodName = "SendString" and + bodyNode = bodySetterCall.getArgument(0) + or + // signature: func (*Ctx).Write(bodies ...interface{}) + methodName = "Write" and + bodyNode = bodySetterCall.getArgument(_) + ) + ) + ) + } + + /** + * Provides models of untrusted flow sources. + */ + private class UntrustedFlowSources extends UntrustedFlowSource::Range { + UntrustedFlowSources() { + // Methods on types of package: github.com/gofiber/fiber@v1.14.6 + exists(string receiverName, string methodName, Method mtd, FunctionOutput out | + this = out.getExitNode(mtd.getACall()) and + mtd.hasQualifiedName(fiberPackagePath(), receiverName, methodName) + | + receiverName = "Ctx" and + ( + // signature: func (*Ctx).BaseURL() string + methodName = "BaseURL" and + out.isResult() + or + // signature: func (*Ctx).Body() string + methodName = "Body" and + out.isResult() + or + // signature: func (*Ctx).BodyParser(out interface{}) error + methodName = "BodyParser" and + out.isParameter(0) + or + // signature: func (*Ctx).Cookies(key string, defaultValue ...string) string + methodName = "Cookies" and + out.isResult() + or + // signature: func (*Ctx).FormFile(key string) (*mime/multipart.FileHeader, error) + methodName = "FormFile" and + out.isResult(0) + or + // signature: func (*Ctx).FormValue(key string) (value string) + methodName = "FormValue" and + out.isResult() + or + // signature: func (*Ctx).Get(key string, defaultValue ...string) string + methodName = "Get" and + out.isResult() + or + // signature: func (*Ctx).Hostname() string + methodName = "Hostname" and + out.isResult() + or + // signature: func (*Ctx).Method(override ...string) string + methodName = "Method" and + out.isResult() + or + // signature: func (*Ctx).MultipartForm() (*mime/multipart.Form, error) + methodName = "MultipartForm" and + out.isResult(0) + or + // signature: func (*Ctx).OriginalURL() string + methodName = "OriginalURL" and + out.isResult() + or + // signature: func (*Ctx).Params(key string, defaultValue ...string) string + methodName = "Params" and + out.isResult() + or + // signature: func (*Ctx).Path(override ...string) string + methodName = "Path" and + out.isResult() + or + // signature: func (*Ctx).Query(key string, defaultValue ...string) string + methodName = "Query" and + out.isResult() + or + // signature: func (*Ctx).QueryParser(out interface{}) error + methodName = "QueryParser" and + out.isParameter(0) + or + // signature: func (*Ctx).Range(size int) (rangeData Range, err error) + methodName = "Range" and + out.isResult(0) + or + // signature: func (*Ctx).Subdomains(offset ...int) []string + methodName = "Subdomains" and + out.isResult() + ) + ) + or + // Structs of package: github.com/gofiber/fiber@v1.14.6 + exists(string structName, string fields, DataFlow::Field fld | + this = fld.getARead() and + fld.hasQualifiedName(fiberPackagePath(), structName, fields) + | + structName = "Cookie" and + fields = ["Domain", "Name", "Path", "SameSite", "Value"] + or + structName = "Error" and + fields = "Message" + ) + } + } +} diff --git a/ql/test/experimental/frameworks/Fiber/HeaderWrite.expected b/ql/test/experimental/frameworks/Fiber/HeaderWrite.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ql/test/experimental/frameworks/Fiber/HeaderWrite.go b/ql/test/experimental/frameworks/Fiber/HeaderWrite.go new file mode 100644 index 00000000000..d32002dfcd6 --- /dev/null +++ b/ql/test/experimental/frameworks/Fiber/HeaderWrite.go @@ -0,0 +1,29 @@ +// Code generated by https://github.com/gagliardetto. DO NOT EDIT. + +package main + +import "github.com/gofiber/fiber" + +// Package github.com/gofiber/fiber@v1.14.6 +func HeaderWrite_GithubComGofiberFiberV1146() { + // Header write via method calls. + { + // Header write via method calls on github.com/gofiber/fiber.Ctx. + { + // func (*Ctx).Append(field string, values ...string) + { + keyString378 := source().(string) + valString541 := source().(string) + var rece fiber.Ctx + rece.Append(keyString378, valString541) // $headerKeyNode=keyString378 $headerValNode=valString541 + } + // func (*Ctx).Set(key string, val string) + { + keyString139 := source().(string) + valString814 := source().(string) + var rece fiber.Ctx + rece.Set(keyString139, valString814) // $headerKeyNode=keyString139 $headerValNode=valString814 + } + } + } +} diff --git a/ql/test/experimental/frameworks/Fiber/HeaderWrite.ql b/ql/test/experimental/frameworks/Fiber/HeaderWrite.ql new file mode 100644 index 00000000000..b04dd80b1b7 --- /dev/null +++ b/ql/test/experimental/frameworks/Fiber/HeaderWrite.ql @@ -0,0 +1,55 @@ +import go +import TestUtilities.InlineExpectationsTest +import experimental.frameworks.Fiber + +class HttpHeaderWriteTest extends InlineExpectationsTest { + HttpHeaderWriteTest() { this = "HttpHeaderWriteTest" } + + override string getARelevantTag() { + result = ["headerKeyNode", "headerValNode", "headerKey", "headerVal"] + } + + override predicate hasActualResult(string file, int line, string element, string tag, string value) { + // Dynamic key-value header: + exists(HTTP::HeaderWrite hw | + hw.hasLocationInfo(file, line, _, _, _) and + ( + element = hw.getName().toString() and + value = hw.getName().toString() and + tag = "headerKeyNode" + or + element = hw.getValue().toString() and + value = hw.getValue().toString() and + tag = "headerValNode" + ) + ) + or + // Static key, dynamic value header: + exists(HTTP::HeaderWrite hw | + hw.hasLocationInfo(file, line, _, _, _) and + ( + element = hw.getHeaderName().toString() and + value = hw.getHeaderName() and + tag = "headerKey" + or + element = hw.getValue().toString() and + value = hw.getValue().toString() and + tag = "headerValNode" + ) + ) + or + // Static key, static value header: + exists(HTTP::HeaderWrite hw | + hw.hasLocationInfo(file, line, _, _, _) and + ( + element = hw.getHeaderName().toString() and + value = hw.getHeaderName() and + tag = "headerKey" + or + element = hw.getHeaderValue().toString() and + value = hw.getHeaderValue() and + tag = "headerVal" + ) + ) + } +} diff --git a/ql/test/experimental/frameworks/Fiber/Redirect.expected b/ql/test/experimental/frameworks/Fiber/Redirect.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ql/test/experimental/frameworks/Fiber/Redirect.go b/ql/test/experimental/frameworks/Fiber/Redirect.go new file mode 100644 index 00000000000..1c92cb941d1 --- /dev/null +++ b/ql/test/experimental/frameworks/Fiber/Redirect.go @@ -0,0 +1,21 @@ +// Code generated by https://github.com/gagliardetto. DO NOT EDIT. + +package main + +import "github.com/gofiber/fiber" + +// Package github.com/gofiber/fiber@v1.14.6 +func Redirect_GithubComGofiberFiberV1146() { + // Redirect via method calls. + { + // Redirect via method calls on github.com/gofiber/fiber.Ctx. + { + // func (*Ctx).Redirect(location string, status ...int) + { + urlString832 := source().(string) + var rece fiber.Ctx + rece.Redirect(urlString832, 0) // $redirectUrl=urlString832 + } + } + } +} diff --git a/ql/test/experimental/frameworks/Fiber/Redirect.ql b/ql/test/experimental/frameworks/Fiber/Redirect.ql new file mode 100644 index 00000000000..0ba2d3adff8 --- /dev/null +++ b/ql/test/experimental/frameworks/Fiber/Redirect.ql @@ -0,0 +1,18 @@ +import go +import TestUtilities.InlineExpectationsTest +import experimental.frameworks.Fiber + +class HttpRedirectTest extends InlineExpectationsTest { + HttpRedirectTest() { this = "HttpRedirectTest" } + + override string getARelevantTag() { result = "redirectUrl" } + + override predicate hasActualResult(string file, int line, string element, string tag, string value) { + tag = "redirectUrl" and + exists(HTTP::Redirect rd | + rd.hasLocationInfo(file, line, _, _, _) and + element = rd.getUrl().toString() and + value = rd.getUrl().toString() + ) + } +} diff --git a/ql/test/experimental/frameworks/Fiber/ResponseBody.expected b/ql/test/experimental/frameworks/Fiber/ResponseBody.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ql/test/experimental/frameworks/Fiber/ResponseBody.go b/ql/test/experimental/frameworks/Fiber/ResponseBody.go new file mode 100644 index 00000000000..74f6bf451a5 --- /dev/null +++ b/ql/test/experimental/frameworks/Fiber/ResponseBody.go @@ -0,0 +1,73 @@ +// Code generated by https://github.com/gagliardetto. DO NOT EDIT. + +package main + +import ( + "io" + + "github.com/gofiber/fiber" +) + +// Package github.com/gofiber/fiber@v1.14.6 +func ResponseBody_GithubComGofiberFiberV1146() { + // Response body is set via a method call (the content-type is implicit in the method name). + { + // Response body is set via a method call on the github.com/gofiber/fiber.Ctx type (the content-type is implicit in the method name). + { + // func (*Ctx).JSON(data interface{}) error + { + bodyInterface768 := source().(interface{}) + var rece fiber.Ctx + rece.JSON(bodyInterface768) // $contentType=application/json $responseBody=bodyInterface768 + } + // func (*Ctx).JSONP(data interface{}, callback ...string) error + { + bodyInterface468 := source().(interface{}) + var rece fiber.Ctx + rece.JSONP(bodyInterface468, "") // $contentType=application/javascript $responseBody=bodyInterface468 + } + } + } + // Response body is set via a call of a type method. + { + // Response body is set via a call of a method on the github.com/gofiber/fiber.Ctx type. + { + // func (*Ctx).Format(body interface{}) + { + bodyInterface736 := source().(interface{}) + var rece fiber.Ctx + rece.Format(bodyInterface736) // $responseBody=bodyInterface736 + } + // func (*Ctx).Send(bodies ...interface{}) + { + bodyInterface516 := source().(interface{}) + var rece fiber.Ctx + rece.Send(bodyInterface516) // $responseBody=bodyInterface516 + } + // func (*Ctx).SendBytes(body []byte) + { + bodyByte246 := source().([]byte) + var rece fiber.Ctx + rece.SendBytes(bodyByte246) // $responseBody=bodyByte246 + } + // func (*Ctx).SendStream(stream io.Reader, size ...int) + { + bodyReader679 := source().(io.Reader) + var rece fiber.Ctx + rece.SendStream(bodyReader679, 0) // $responseBody=bodyReader679 + } + // func (*Ctx).SendString(body string) + { + bodyString736 := source().(string) + var rece fiber.Ctx + rece.SendString(bodyString736) // $responseBody=bodyString736 + } + // func (*Ctx).Write(bodies ...interface{}) + { + bodyInterface839 := source().(interface{}) + var rece fiber.Ctx + rece.Write(bodyInterface839) // $responseBody=bodyInterface839 + } + } + } +} diff --git a/ql/test/experimental/frameworks/Fiber/ResponseBody.ql b/ql/test/experimental/frameworks/Fiber/ResponseBody.ql new file mode 100644 index 00000000000..d089b419f7f --- /dev/null +++ b/ql/test/experimental/frameworks/Fiber/ResponseBody.ql @@ -0,0 +1,24 @@ +import go +import TestUtilities.InlineExpectationsTest +import experimental.frameworks.Fiber + +class HttpResponseBodyTest extends InlineExpectationsTest { + HttpResponseBodyTest() { this = "HttpResponseBodyTest" } + + override string getARelevantTag() { result = ["contentType", "responseBody"] } + + override predicate hasActualResult(string file, int line, string element, string tag, string value) { + exists(HTTP::ResponseBody rd | + rd.hasLocationInfo(file, line, _, _, _) and + ( + element = rd.getAContentType().toString() and + value = rd.getAContentType().toString() and + tag = "contentType" + or + element = rd.toString() and + value = rd.toString() and + tag = "responseBody" + ) + ) + } +} diff --git a/ql/test/experimental/frameworks/Fiber/TaintTracking.expected b/ql/test/experimental/frameworks/Fiber/TaintTracking.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ql/test/experimental/frameworks/Fiber/TaintTracking.go b/ql/test/experimental/frameworks/Fiber/TaintTracking.go new file mode 100644 index 00000000000..0dd551d7425 --- /dev/null +++ b/ql/test/experimental/frameworks/Fiber/TaintTracking.go @@ -0,0 +1,106 @@ +// Code generated by https://github.com/gagliardetto. DO NOT EDIT. + +package main + +import ( + "github.com/gofiber/fiber" + "github.com/gofiber/utils" +) + +// Package github.com/gofiber/fiber@v1.14.6 +func TaintTracking_GithubComGofiberFiberV1146() { + // Taint-tracking through functions. + { + // func NewError(code int, message ...string) *Error + { + fromString656 := source().(string) + intoError414 := fiber.NewError(0, fromString656) + sink(intoError414) // $taintSink + } + } +} + +// Package github.com/gofiber/utils@v0.0.10 +func TaintTracking_GithubComGofiberUtilsV0010() { + // Taint-tracking through functions. + { + // func GetBytes(s string) []byte + { + fromString989 := source().(string) + intoByte982 := utils.GetBytes(fromString989) + sink(intoByte982) // $taintSink + } + // func GetString(b []byte) string + { + fromByte417 := source().([]byte) + intoString584 := utils.GetString(fromByte417) + sink(intoString584) // $taintSink + } + // func ImmutableString(s string) string + { + fromString991 := source().(string) + intoString881 := utils.ImmutableString(fromString991) + sink(intoString881) // $taintSink + } + // func ToLower(b string) string + { + fromString494 := source().(string) + intoString873 := utils.ToLower(fromString494) + sink(intoString873) // $taintSink + } + // func ToLowerBytes(b []byte) []byte + { + fromByte599 := source().([]byte) + intoByte409 := utils.ToLowerBytes(fromByte599) + sink(intoByte409) // $taintSink + } + // func ToUpper(b string) string + { + fromString246 := source().(string) + intoString898 := utils.ToUpper(fromString246) + sink(intoString898) // $taintSink + } + // func ToUpperBytes(b []byte) []byte + { + fromByte598 := source().([]byte) + intoByte631 := utils.ToUpperBytes(fromByte598) + sink(intoByte631) // $taintSink + } + // func Trim(s string, cutset byte) string + { + fromString165 := source().(string) + intoString150 := utils.Trim(fromString165, 0) + sink(intoString150) // $taintSink + } + // func TrimBytes(b []byte, cutset byte) []byte + { + fromByte340 := source().([]byte) + intoByte471 := utils.TrimBytes(fromByte340, 0) + sink(intoByte471) // $taintSink + } + // func TrimLeft(s string, cutset byte) string + { + fromString290 := source().(string) + intoString758 := utils.TrimLeft(fromString290, 0) + sink(intoString758) // $taintSink + } + // func TrimLeftBytes(b []byte, cutset byte) []byte + { + fromByte396 := source().([]byte) + intoByte707 := utils.TrimLeftBytes(fromByte396, 0) + sink(intoByte707) // $taintSink + } + // func TrimRight(s string, cutset byte) string + { + fromString912 := source().(string) + intoString718 := utils.TrimRight(fromString912, 0) + sink(intoString718) // $taintSink + } + // func TrimRightBytes(b []byte, cutset byte) []byte + { + fromByte972 := source().([]byte) + intoByte633 := utils.TrimRightBytes(fromByte972, 0) + sink(intoByte633) // $taintSink + } + } +} diff --git a/ql/test/experimental/frameworks/Fiber/TaintTracking.ql b/ql/test/experimental/frameworks/Fiber/TaintTracking.ql new file mode 100644 index 00000000000..2b5eb4fb958 --- /dev/null +++ b/ql/test/experimental/frameworks/Fiber/TaintTracking.ql @@ -0,0 +1,30 @@ +import go +import TestUtilities.InlineExpectationsTest +import experimental.frameworks.Fiber + +class Configuration extends TaintTracking::Configuration { + Configuration() { this = "test-configuration" } + + override predicate isSource(DataFlow::Node source) { + exists(Function fn | fn.hasQualifiedName(_, "source") | source = fn.getACall().getResult()) + } + + override predicate isSink(DataFlow::Node sink) { + exists(Function fn | fn.hasQualifiedName(_, "sink") | sink = fn.getACall().getAnArgument()) + } +} + +class TaintTrackingTest extends InlineExpectationsTest { + TaintTrackingTest() { this = "TaintTrackingTest" } + + override string getARelevantTag() { result = "taintSink" } + + override predicate hasActualResult(string file, int line, string element, string tag, string value) { + tag = "taintSink" and + exists(DataFlow::Node sink | any(Configuration c).hasFlow(_, sink) | + element = sink.toString() and + value = "" and + sink.hasLocationInfo(file, line, _, _, _) + ) + } +} diff --git a/ql/test/experimental/frameworks/Fiber/UntrustedFlowSources.expected b/ql/test/experimental/frameworks/Fiber/UntrustedFlowSources.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ql/test/experimental/frameworks/Fiber/UntrustedFlowSources.go b/ql/test/experimental/frameworks/Fiber/UntrustedFlowSources.go new file mode 100644 index 00000000000..23f2afe87a2 --- /dev/null +++ b/ql/test/experimental/frameworks/Fiber/UntrustedFlowSources.go @@ -0,0 +1,138 @@ +// Code generated by https://github.com/gagliardetto. DO NOT EDIT. + +package main + +import "github.com/gofiber/fiber" + +// Package github.com/gofiber/fiber@v1.14.6 +func UntrustedFlowSources_GithubComGofiberFiberV1146() { + // Untrusted flow sources from method calls. + { + // Untrusted flow sources from method calls on github.com/gofiber/fiber.Ctx. + { + // func (*Ctx).BaseURL() string + { + var receiverCtx273 fiber.Ctx + result982 := receiverCtx273.BaseURL() + sink(result982) // $untrustedFlowSource + } + // func (*Ctx).Body() string + { + var receiverCtx458 fiber.Ctx + result506 := receiverCtx458.Body() + sink(result506) // $untrustedFlowSource + } + // func (*Ctx).BodyParser(out interface{}) error + { + var receiverCtx213 fiber.Ctx + var paramOut468 interface{} + receiverCtx213.BodyParser(paramOut468) + sink(paramOut468) // $untrustedFlowSource + } + // func (*Ctx).Cookies(key string, defaultValue ...string) string + { + var receiverCtx219 fiber.Ctx + result265 := receiverCtx219.Cookies("", "") + sink(result265) // $untrustedFlowSource + } + // func (*Ctx).FormFile(key string) (*mime/multipart.FileHeader, error) + { + var receiverCtx971 fiber.Ctx + result320, _ := receiverCtx971.FormFile("") + sink(result320) // $untrustedFlowSource + } + // func (*Ctx).FormValue(key string) (value string) + { + var receiverCtx545 fiber.Ctx + resultValue566 := receiverCtx545.FormValue("") + sink(resultValue566) // $untrustedFlowSource + } + // func (*Ctx).Get(key string, defaultValue ...string) string + { + var receiverCtx497 fiber.Ctx + result274 := receiverCtx497.Get("", "") + sink(result274) // $untrustedFlowSource + } + // func (*Ctx).Hostname() string + { + var receiverCtx783 fiber.Ctx + result905 := receiverCtx783.Hostname() + sink(result905) // $untrustedFlowSource + } + // func (*Ctx).Method(override ...string) string + { + var receiverCtx389 fiber.Ctx + result198 := receiverCtx389.Method("") + sink(result198) // $untrustedFlowSource + } + // func (*Ctx).MultipartForm() (*mime/multipart.Form, error) + { + var receiverCtx477 fiber.Ctx + result544, _ := receiverCtx477.MultipartForm() + sink(result544) // $untrustedFlowSource + } + // func (*Ctx).OriginalURL() string + { + var receiverCtx382 fiber.Ctx + result715 := receiverCtx382.OriginalURL() + sink(result715) // $untrustedFlowSource + } + // func (*Ctx).Params(key string, defaultValue ...string) string + { + var receiverCtx179 fiber.Ctx + result366 := receiverCtx179.Params("", "") + sink(result366) // $untrustedFlowSource + } + // func (*Ctx).Path(override ...string) string + { + var receiverCtx648 fiber.Ctx + result544 := receiverCtx648.Path("") + sink(result544) // $untrustedFlowSource + } + // func (*Ctx).Query(key string, defaultValue ...string) string + { + var receiverCtx754 fiber.Ctx + result680 := receiverCtx754.Query("", "") + sink(result680) // $untrustedFlowSource + } + // func (*Ctx).QueryParser(out interface{}) error + { + var receiverCtx722 fiber.Ctx + var paramOut506 interface{} + receiverCtx722.QueryParser(paramOut506) + sink(paramOut506) // $untrustedFlowSource + } + // func (*Ctx).Range(size int) (rangeData Range, err error) + { + var receiverCtx121 fiber.Ctx + resultRangeData293, _ := receiverCtx121.Range(0) + sink(resultRangeData293) // $untrustedFlowSource + } + // func (*Ctx).Subdomains(offset ...int) []string + { + var receiverCtx151 fiber.Ctx + result849 := receiverCtx151.Subdomains(0) + sink(result849) // $untrustedFlowSource + } + } + } + // Untrusted flow sources from struct fields. + { + // Untrusted flow sources from github.com/gofiber/fiber.Cookie struct fields. + { + structCookie322 := new(fiber.Cookie) + sink( + structCookie322.Domain, // $untrustedFlowSource + structCookie322.Name, // $untrustedFlowSource + structCookie322.Path, // $untrustedFlowSource + structCookie322.SameSite, // $untrustedFlowSource + structCookie322.Value, // $untrustedFlowSource + ) + } + // Untrusted flow sources from github.com/gofiber/fiber.Error struct fields. + { + structError339 := new(fiber.Error) + sink(structError339.Message) // $untrustedFlowSource + } + } +} diff --git a/ql/test/experimental/frameworks/Fiber/UntrustedFlowSources.ql b/ql/test/experimental/frameworks/Fiber/UntrustedFlowSources.ql new file mode 100644 index 00000000000..cb039c5b6d2 --- /dev/null +++ b/ql/test/experimental/frameworks/Fiber/UntrustedFlowSources.ql @@ -0,0 +1,22 @@ +import go +import TestUtilities.InlineExpectationsTest +import experimental.frameworks.Fiber + +class UntrustedFlowSourceTest extends InlineExpectationsTest { + UntrustedFlowSourceTest() { this = "UntrustedFlowSourceTest" } + + override string getARelevantTag() { result = "untrustedFlowSource" } + + override predicate hasActualResult(string file, int line, string element, string tag, string value) { + tag = "untrustedFlowSource" and + exists(DataFlow::CallNode sinkCall, DataFlow::ArgumentNode arg | + sinkCall.getCalleeName() = "sink" and + arg = sinkCall.getAnArgument() and + arg.getAPredecessor*() instanceof UntrustedFlowSource + | + element = arg.toString() and + value = "" and + arg.hasLocationInfo(file, line, _, _, _) + ) + } +} diff --git a/ql/test/experimental/frameworks/Fiber/go.mod b/ql/test/experimental/frameworks/Fiber/go.mod new file mode 100755 index 00000000000..02416704e76 --- /dev/null +++ b/ql/test/experimental/frameworks/Fiber/go.mod @@ -0,0 +1,8 @@ +module example.com/hello/world + +go 1.15 + +require ( + github.com/gofiber/fiber v1.14.6 + github.com/gofiber/utils v0.0.10 +) diff --git a/ql/test/experimental/frameworks/Fiber/stubs.go b/ql/test/experimental/frameworks/Fiber/stubs.go new file mode 100644 index 00000000000..d435852dedb --- /dev/null +++ b/ql/test/experimental/frameworks/Fiber/stubs.go @@ -0,0 +1,12 @@ +//go:generate depstubber --vendor --auto +package main + +func main() {} + +func source() interface{} { + return nil +} + +func sink(v ...interface{}) {} + +func link(from interface{}, into interface{}) {} diff --git a/ql/test/experimental/frameworks/Fiber/vendor/github.com/gofiber/fiber/LICENSE b/ql/test/experimental/frameworks/Fiber/vendor/github.com/gofiber/fiber/LICENSE new file mode 100644 index 00000000000..51201f1f6e2 --- /dev/null +++ b/ql/test/experimental/frameworks/Fiber/vendor/github.com/gofiber/fiber/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019-2020 Fenny and Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/ql/test/experimental/frameworks/Fiber/vendor/github.com/gofiber/fiber/stub.go b/ql/test/experimental/frameworks/Fiber/vendor/github.com/gofiber/fiber/stub.go new file mode 100644 index 00000000000..1b0aaa47308 --- /dev/null +++ b/ql/test/experimental/frameworks/Fiber/vendor/github.com/gofiber/fiber/stub.go @@ -0,0 +1,415 @@ +// Code generated by depstubber. DO NOT EDIT. +// This is a simple stub for github.com/gofiber/fiber, strictly for use in testing. + +// See the LICENSE file for information about the licensing of the original library. +// Source: github.com/gofiber/fiber (exports: Cookie,Ctx,Error; functions: NewError) + +// Package fiber is a stub of github.com/gofiber/fiber, generated by depstubber. +package fiber + +import ( + context "context" + tls "crypto/tls" + io "io" + multipart "mime/multipart" + net "net" + http "net/http" + time "time" +) + +type App struct { + Settings *Settings +} + +func (_ *App) AcquireCtx(_ interface{}) *Ctx { + return nil +} + +func (_ *App) Add(_ string, _ string, _ ...func(*Ctx)) Router { + return nil +} + +func (_ *App) All(_ string, _ ...func(*Ctx)) Router { + return nil +} + +func (_ *App) Connect(_ string, _ ...func(*Ctx)) Router { + return nil +} + +func (_ *App) Delete(_ string, _ ...func(*Ctx)) Router { + return nil +} + +func (_ *App) Get(_ string, _ ...func(*Ctx)) Router { + return nil +} + +func (_ *App) Group(_ string, _ ...func(*Ctx)) Router { + return nil +} + +func (_ *App) Handler() interface{} { + return nil +} + +func (_ *App) Head(_ string, _ ...func(*Ctx)) Router { + return nil +} + +func (_ *App) IsChild() bool { + return false +} + +func (_ *App) Listen(_ interface{}, _ ...*tls.Config) error { + return nil +} + +func (_ *App) Listener(_ net.Listener, _ ...*tls.Config) error { + return nil +} + +func (_ *App) Options(_ string, _ ...func(*Ctx)) Router { + return nil +} + +func (_ *App) Patch(_ string, _ ...func(*Ctx)) Router { + return nil +} + +func (_ *App) Post(_ string, _ ...func(*Ctx)) Router { + return nil +} + +func (_ *App) Put(_ string, _ ...func(*Ctx)) Router { + return nil +} + +func (_ *App) ReleaseCtx(_ *Ctx) {} + +func (_ *App) Routes() []*Route { + return nil +} + +func (_ *App) Shutdown() error { + return nil +} + +func (_ *App) Stack() [][]*Route { + return nil +} + +func (_ *App) Static(_ string, _ string, _ ...Static) Router { + return nil +} + +func (_ *App) Test(_ *http.Request, _ ...int) (*http.Response, error) { + return nil, nil +} + +func (_ *App) Trace(_ string, _ ...func(*Ctx)) Router { + return nil +} + +func (_ *App) Use(_ ...interface{}) Router { + return nil +} + +type Cookie struct { + Name string + Value string + Path string + Domain string + Expires time.Time + Secure bool + HTTPOnly bool + SameSite string +} + +type Ctx struct { + Fasthttp interface{} +} + +func (_ *Ctx) Accepts(_ ...string) string { + return "" +} + +func (_ *Ctx) AcceptsCharsets(_ ...string) string { + return "" +} + +func (_ *Ctx) AcceptsEncodings(_ ...string) string { + return "" +} + +func (_ *Ctx) AcceptsLanguages(_ ...string) string { + return "" +} + +func (_ *Ctx) App() *App { + return nil +} + +func (_ *Ctx) Append(_ string, _ ...string) {} + +func (_ *Ctx) Attachment(_ ...string) {} + +func (_ *Ctx) BaseURL() string { + return "" +} + +func (_ *Ctx) Body() string { + return "" +} + +func (_ *Ctx) BodyParser(_ interface{}) error { + return nil +} + +func (_ *Ctx) ClearCookie(_ ...string) {} + +func (_ *Ctx) Context() context.Context { + return nil +} + +func (_ *Ctx) Cookie(_ *Cookie) {} + +func (_ *Ctx) Cookies(_ string, _ ...string) string { + return "" +} + +func (_ *Ctx) Download(_ string, _ ...string) error { + return nil +} + +func (_ *Ctx) Error() error { + return nil +} + +func (_ *Ctx) FormFile(_ string) (*multipart.FileHeader, error) { + return nil, nil +} + +func (_ *Ctx) FormValue(_ string) string { + return "" +} + +func (_ *Ctx) Format(_ interface{}) {} + +func (_ *Ctx) Fresh() bool { + return false +} + +func (_ *Ctx) Get(_ string, _ ...string) string { + return "" +} + +func (_ *Ctx) Hostname() string { + return "" +} + +func (_ *Ctx) IP() string { + return "" +} + +func (_ *Ctx) IPs() []string { + return nil +} + +func (_ *Ctx) Is(_ string) bool { + return false +} + +func (_ *Ctx) JSON(_ interface{}) error { + return nil +} + +func (_ *Ctx) JSONP(_ interface{}, _ ...string) error { + return nil +} + +func (_ *Ctx) Links(_ ...string) {} + +func (_ *Ctx) Locals(_ string, _ ...interface{}) interface{} { + return nil +} + +func (_ *Ctx) Location(_ string) {} + +func (_ *Ctx) Method(_ ...string) string { + return "" +} + +func (_ *Ctx) MultipartForm() (*multipart.Form, error) { + return nil, nil +} + +func (_ *Ctx) Next(_ ...error) {} + +func (_ *Ctx) OriginalURL() string { + return "" +} + +func (_ *Ctx) Params(_ string, _ ...string) string { + return "" +} + +func (_ *Ctx) Path(_ ...string) string { + return "" +} + +func (_ *Ctx) Protocol() string { + return "" +} + +func (_ *Ctx) Query(_ string, _ ...string) string { + return "" +} + +func (_ *Ctx) QueryParser(_ interface{}) error { + return nil +} + +func (_ *Ctx) Range(_ int) (Range, error) { + return Range{}, nil +} + +func (_ *Ctx) Redirect(_ string, _ ...int) {} + +func (_ *Ctx) Render(_ string, _ interface{}, _ ...string) error { + return nil +} + +func (_ *Ctx) Route() *Route { + return nil +} + +func (_ *Ctx) SaveFile(_ *multipart.FileHeader, _ string) error { + return nil +} + +func (_ *Ctx) Secure() bool { + return false +} + +func (_ *Ctx) Send(_ ...interface{}) {} + +func (_ *Ctx) SendBytes(_ []byte) {} + +func (_ *Ctx) SendFile(_ string, _ ...bool) error { + return nil +} + +func (_ *Ctx) SendStatus(_ int) {} + +func (_ *Ctx) SendStream(_ io.Reader, _ ...int) {} + +func (_ *Ctx) SendString(_ string) {} + +func (_ *Ctx) Set(_ string, _ string) {} + +func (_ *Ctx) Stale() bool { + return false +} + +func (_ *Ctx) Status(_ int) *Ctx { + return nil +} + +func (_ *Ctx) Subdomains(_ ...int) []string { + return nil +} + +func (_ *Ctx) Type(_ string, _ ...string) *Ctx { + return nil +} + +func (_ *Ctx) Vary(_ ...string) {} + +func (_ *Ctx) Write(_ ...interface{}) {} + +func (_ *Ctx) XHR() bool { + return false +} + +type Error struct { + Code int + Message string +} + +func (_ *Error) Error() string { + return "" +} + +func NewError(_ int, _ ...string) *Error { + return nil +} + +type Range struct { + Type string + Ranges []struct { + Start int + End int + } +} + +type Route struct { + Method string + Path string + Params []string + Handlers []func(*Ctx) +} + +type Router interface { + Add(_ string, _ string, _ ...func(*Ctx)) Router + All(_ string, _ ...func(*Ctx)) Router + Connect(_ string, _ ...func(*Ctx)) Router + Delete(_ string, _ ...func(*Ctx)) Router + Get(_ string, _ ...func(*Ctx)) Router + Group(_ string, _ ...func(*Ctx)) Router + Head(_ string, _ ...func(*Ctx)) Router + Options(_ string, _ ...func(*Ctx)) Router + Patch(_ string, _ ...func(*Ctx)) Router + Post(_ string, _ ...func(*Ctx)) Router + Put(_ string, _ ...func(*Ctx)) Router + Static(_ string, _ string, _ ...Static) Router + Trace(_ string, _ ...func(*Ctx)) Router + Use(_ ...interface{}) Router +} + +type Settings struct { + ErrorHandler func(*Ctx, error) + ServerHeader string + StrictRouting bool + CaseSensitive bool + Immutable bool + UnescapePath bool + ETag bool + Prefork bool + BodyLimit int + Concurrency int + DisableKeepalive bool + DisableDefaultDate bool + DisableDefaultContentType bool + DisableHeaderNormalizing bool + DisableStartupMessage bool + Views Views + ReadTimeout time.Duration + WriteTimeout time.Duration + IdleTimeout time.Duration + ReadBufferSize int + WriteBufferSize int + CompressedFileSuffix string +} + +type Static struct { + Compress bool + ByteRange bool + Browse bool + Index string +} + +type Views interface { + Load() error + Render(_ io.Writer, _ string, _ interface{}, _ ...string) error +} diff --git a/ql/test/experimental/frameworks/Fiber/vendor/github.com/gofiber/utils/LICENSE b/ql/test/experimental/frameworks/Fiber/vendor/github.com/gofiber/utils/LICENSE new file mode 100644 index 00000000000..ca80106ea6b --- /dev/null +++ b/ql/test/experimental/frameworks/Fiber/vendor/github.com/gofiber/utils/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Fiber + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/ql/test/experimental/frameworks/Fiber/vendor/github.com/gofiber/utils/stub.go b/ql/test/experimental/frameworks/Fiber/vendor/github.com/gofiber/utils/stub.go new file mode 100644 index 00000000000..0504ea3cc3f --- /dev/null +++ b/ql/test/experimental/frameworks/Fiber/vendor/github.com/gofiber/utils/stub.go @@ -0,0 +1,60 @@ +// Code generated by depstubber. DO NOT EDIT. +// This is a simple stub for github.com/gofiber/utils, strictly for use in testing. + +// See the LICENSE file for information about the licensing of the original library. +// Source: github.com/gofiber/utils (exports: ; functions: GetBytes,GetString,ImmutableString,ToLower,ToLowerBytes,ToUpper,ToUpperBytes,Trim,TrimBytes,TrimLeft,TrimLeftBytes,TrimRight,TrimRightBytes) + +// Package utils is a stub of github.com/gofiber/utils, generated by depstubber. +package utils + +func GetBytes(_ string) []byte { + return nil +} + +func GetString(_ []byte) string { + return "" +} + +func ImmutableString(_ string) string { + return "" +} + +func ToLower(_ string) string { + return "" +} + +func ToLowerBytes(_ []byte) []byte { + return nil +} + +func ToUpper(_ string) string { + return "" +} + +func ToUpperBytes(_ []byte) []byte { + return nil +} + +func Trim(_ string, _ byte) string { + return "" +} + +func TrimBytes(_ []byte, _ byte) []byte { + return nil +} + +func TrimLeft(_ string, _ byte) string { + return "" +} + +func TrimLeftBytes(_ []byte, _ byte) []byte { + return nil +} + +func TrimRight(_ string, _ byte) string { + return "" +} + +func TrimRightBytes(_ []byte, _ byte) []byte { + return nil +} diff --git a/ql/test/experimental/frameworks/Fiber/vendor/modules.txt b/ql/test/experimental/frameworks/Fiber/vendor/modules.txt new file mode 100644 index 00000000000..61d00746b7d --- /dev/null +++ b/ql/test/experimental/frameworks/Fiber/vendor/modules.txt @@ -0,0 +1,6 @@ +# github.com/gofiber/fiber v1.14.6 +## explicit +github.com/gofiber/fiber +# github.com/gofiber/utils v0.0.10 +## explicit +github.com/gofiber/utils