diff --git a/ql/src/experimental/CWE-1004/AuthCookie.qll b/ql/src/experimental/CWE-1004/AuthCookie.qll new file mode 100644 index 00000000000..34e17ca1cfd --- /dev/null +++ b/ql/src/experimental/CWE-1004/AuthCookie.qll @@ -0,0 +1,165 @@ +import go + +/** + * A simplistic points-to alternative: given a struct creation and a field name, get the values that field can be assigned. + * + * Assumptions: + * - we don't reassign the variable that the creation is stored in + * - we always access the creation through the same variable it is initially assigned to + * + * This should cover most typical patterns... + */ +DataFlow::Node getValueForFieldWrite(StructLit sl, string field) { + exists(Write w, DataFlow::Node base, Field f, DataFlow::Node rhs | + f.getName() = field and + w.writesField(base, f, rhs) and + result = rhs and + ( + sl = base.asExpr() + or + exists(VariableName vn | + vn = base.asExpr() and + exists(DataFlow::Node creation | + DataFlow::localFlow(creation, base) and + creation.asExpr() = sl and + base.asExpr() = vn + ) + ) + ) + ) +} + +/** + * Tracks struct creation without `HttpOnly` to `SetCookie`. + */ +class HttpOnlyCookieTrackingConfiguration extends TaintTracking::Configuration { + HttpOnlyCookieTrackingConfiguration() { this = "HttpOnlyCookieTrackingConfiguration" } + + override predicate isSource(DataFlow::Node source) { + exists(StructLit sl | + source.asExpr() = sl and + sl.getType().hasQualifiedName("net/http", "Cookie") and + ( + not exists(DataFlow::Node rhs | rhs = getValueForFieldWrite(sl, "HttpOnly")) + or + exists(DataFlow::Node rhs | + rhs = getValueForFieldWrite(sl, "HttpOnly") and + exists(DataFlow::Node valSrc | + DataFlow::localFlow(valSrc, rhs) and + valSrc.asExpr().getBoolValue() = false + ) + ) + ) + ) + } + + override predicate isSink(DataFlow::Node sink) { sink instanceof SetCookieSink } +} + +/** + * A cookie passed the second parameter to `SetCookie`. + */ +class SetCookieSink extends DataFlow::Node { + SetCookieSink() { + exists(CallExpr c | + c.getTarget().hasQualifiedName("net/http", "SetCookie") and + this.asExpr() = c.getArgument(1) + ) + } +} + +/** + * Holds if the expression or its value has a sensitive name + */ +predicate isAuthVariable(Expr expr) { + exists(string val | + ( + val = expr.getStringValue() or + val = expr.(Name).getTarget().getName() + ) and + val.regexpMatch("(?i).*(session|login|token|user|auth|credential).*") and + not val.regexpMatch("(?i).*(xsrf|csrf|forgery).*") + ) +} + +/** + * Tracks if a variable with a sensitive name is used as a cookie name. + */ +class AuthCookieNameConfiguration extends TaintTracking::Configuration { + AuthCookieNameConfiguration() { this = "AuthCookieNameConfiguration" } + + override predicate isSource(DataFlow::Node source) { + exists(StructLit sl | + source.asExpr() = sl and + sl.getType().hasQualifiedName("net/http", "Cookie") and + exists(DataFlow::Node rhs | + rhs = getValueForFieldWrite(sl, "Name") and + exists(DataFlow::Node valSrc | + DataFlow::localFlow(valSrc, rhs) and + isAuthVariable(valSrc.asExpr()) + ) + ) + ) + } + + override predicate isSink(DataFlow::Node sink) { sink instanceof SetCookieSink } +} + +/** + * Tracks from gorilla cookie store creation to session save. + */ +class CookieStoreSaveTrackingConfiguration extends DataFlow::Configuration { + CookieStoreSaveTrackingConfiguration() { this = "CookieStoreSaveTrackingConfiguration" } + + override predicate isSource(DataFlow::Node source) { + exists(CallExpr c | + source.asExpr() = c and + c.getTarget().hasQualifiedName("github.com/gorilla/sessions", "NewCookieStore") + ) + } + + override predicate isSink(DataFlow::Node sink) { + exists(CallExpr c | + sink.asExpr() = c.getCalleeExpr().(SelectorExpr).getBase() and + c.getTarget().getQualifiedName() = "github.com/gorilla/sessions.Session.Save" + ) + } + + override predicate isAdditionalFlowStep(DataFlow::Node pred, DataFlow::Node succ) { + exists(Function f, DataFlow::CallNode cn | cn = f.getACall() | + f.getQualifiedName() = "github.com/gorilla/sessions.CookieStore.Get" and + pred = cn.getReceiver() and + succ = cn.getResult(0) + ) + } +} + +/** + * Tracks session options to session save. + */ +class SessionOptionsTrackingConfiguration extends TaintTracking::Configuration { + SessionOptionsTrackingConfiguration() { this = "SessionOptionsTrackingConfiguration" } + + override predicate isSource(DataFlow::Node source) { + exists(StructLit sl | + sl.getType().hasQualifiedName("github.com/gorilla/sessions", "Options") and + source.asExpr() = sl + ) + } + + override predicate isSink(DataFlow::Node sink) { + exists(CallExpr c | + sink.asExpr() = c.getCalleeExpr().(SelectorExpr).getBase() and + c.getTarget().getQualifiedName() = "github.com/gorilla/sessions.Session.Save" + ) + } + + override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) { + exists(Field f, DataFlow::Write w, DataFlow::Node base | + f.getQualifiedName() = "github.com/gorilla/sessions.Session.Options" and + w.writesField(base, f, _) and + pred = w.getRhs() and + succ = base + ) + } +} diff --git a/ql/src/experimental/CWE-1004/CookieWithoutHttpOnly.qhelp b/ql/src/experimental/CWE-1004/CookieWithoutHttpOnly.qhelp new file mode 100644 index 00000000000..2e88a610c9d --- /dev/null +++ b/ql/src/experimental/CWE-1004/CookieWithoutHttpOnly.qhelp @@ -0,0 +1,42 @@ + + + + +

+Cookies without HttpOnly attribute are accessible to JavaScript running in the same origin. In case of +Cross-Site Scripting (XSS) vulnerability the cookie can be stolen by malicious script. +

+
+ + +

+Protect sensitive cookies, such as related to authentication, by setting HttpOnly to true to make +them not accessible to JavaScript. +

+
+ + + +

+In the following example the default HttpOnly value is false. +

+ + + +

+In the example below HttpOnly is set to true. +

+ + + +
+ + + +
  • type Cookie,
  • +
  • Set-Cookie Header,
  • + +
    +
    \ No newline at end of file diff --git a/ql/src/experimental/CWE-1004/CookieWithoutHttpOnly.ql b/ql/src/experimental/CWE-1004/CookieWithoutHttpOnly.ql new file mode 100644 index 00000000000..5f49a361608 --- /dev/null +++ b/ql/src/experimental/CWE-1004/CookieWithoutHttpOnly.ql @@ -0,0 +1,63 @@ +/** + * @name 'HttpOnly' attribute is not set to true + * @description Omitting the 'HttpOnly' attribute for security sensitive data allows + * malicious JavaScript to steal it in case of XSS vulnerability. Always set + * 'HttpOnly' to 'true' to authentication related cookie to make it + * not accessible by JavaScript. + * @kind problem + * @problem.severity warning + * @precision high + * @id go/cookie-httponly-not-set + * @tags security + * external/cwe/cwe-1004 + */ + +import go +import AuthCookie + +from Expr expr +where + exists(SetCookieSink sink, DataFlow::Node source | + exists(HttpOnlyCookieTrackingConfiguration httpOnlyCfg | httpOnlyCfg.hasFlow(source, sink)) and + exists(AuthCookieNameConfiguration cookieNameCfg | cookieNameCfg.hasFlow(source, sink)) and + sink.asExpr() = expr + ) + or + exists(CallExpr c | + c.getTarget().getQualifiedName() = "github.com/gin-gonic/gin.Context.SetCookie" and + c.getArgument(6) = expr and + exists(DataFlow::Node valSrc, DataFlow::Node httpOnlyArg | + DataFlow::localFlow(valSrc, httpOnlyArg) and + httpOnlyArg.asExpr() = c.getArgument(6) and + valSrc.asExpr().getBoolValue() = false + ) and + exists(DataFlow::Node nameSrc, DataFlow::Node nameArg | + DataFlow::localFlow(nameSrc, nameArg) and + nameArg.asExpr() = c.getArgument(0) and + isAuthVariable(nameSrc.asExpr()) + ) + ) + or + exists(DataFlow::Node sessionSave | + sessionSave.asExpr() = expr and + exists(CookieStoreSaveTrackingConfiguration cfg | cfg.hasFlow(_, sessionSave)) and + ( + not exists(SessionOptionsTrackingConfiguration cfg | cfg.hasFlow(_, sessionSave)) + or + exists(SessionOptionsTrackingConfiguration cfg, DataFlow::Node options | + cfg.hasFlow(options, sessionSave) and + ( + not exists(DataFlow::Node rhs | rhs = getValueForFieldWrite(options.asExpr(), "HttpOnly")) + or + exists(DataFlow::Node rhs | + rhs = getValueForFieldWrite(options.asExpr(), "HttpOnly") and + exists(DataFlow::Node valSrc | + DataFlow::localFlow(valSrc, rhs) and + valSrc.asExpr().getBoolValue() = false + ) + ) + ) + ) + ) + ) +select expr, "Cookie attribute 'HttpOnly' is not set to true." diff --git a/ql/src/experimental/CWE-1004/CookieWithoutHttpOnlyBad.go b/ql/src/experimental/CWE-1004/CookieWithoutHttpOnlyBad.go new file mode 100644 index 00000000000..852e2f3f3db --- /dev/null +++ b/ql/src/experimental/CWE-1004/CookieWithoutHttpOnlyBad.go @@ -0,0 +1,17 @@ +package main + +import ( + "net/http" +) + +func handler(w http.ResponseWriter, r *http.Request) { + c := http.Cookie{ + Name: "session", + Value: "secret", + } + http.SetCookie(w, &c) +} + +func main() { + http.HandleFunc("/", handler) +} diff --git a/ql/src/experimental/CWE-1004/CookieWithoutHttpOnlyGood.go b/ql/src/experimental/CWE-1004/CookieWithoutHttpOnlyGood.go new file mode 100644 index 00000000000..b0b505e2007 --- /dev/null +++ b/ql/src/experimental/CWE-1004/CookieWithoutHttpOnlyGood.go @@ -0,0 +1,18 @@ +package main + +import ( + "net/http" +) + +func handler(w http.ResponseWriter, r *http.Request) { + c := http.Cookie{ + Name: "session", + Value: "secret", + HttpOnly: true, + } + http.SetCookie(w, &c) +} + +func main() { + http.HandleFunc("/", handler) +} diff --git a/ql/test/experimental/CWE-1004/CookieWithoutHttpOnly.expected b/ql/test/experimental/CWE-1004/CookieWithoutHttpOnly.expected new file mode 100644 index 00000000000..5c4e2c3d2e7 --- /dev/null +++ b/ql/test/experimental/CWE-1004/CookieWithoutHttpOnly.expected @@ -0,0 +1,11 @@ +| CookieWithoutHttpOnly.go:14:20:14:21 | &... | Cookie attribute 'HttpOnly' is not set to true. | +| CookieWithoutHttpOnly.go:23:20:23:21 | &... | Cookie attribute 'HttpOnly' is not set to true. | +| CookieWithoutHttpOnly.go:50:20:50:21 | &... | Cookie attribute 'HttpOnly' is not set to true. | +| CookieWithoutHttpOnly.go:60:20:60:21 | &... | Cookie attribute 'HttpOnly' is not set to true. | +| CookieWithoutHttpOnly.go:90:20:90:21 | &... | Cookie attribute 'HttpOnly' is not set to true. | +| CookieWithoutHttpOnly.go:109:20:109:21 | &... | Cookie attribute 'HttpOnly' is not set to true. | +| CookieWithoutHttpOnly.go:119:20:119:21 | &... | Cookie attribute 'HttpOnly' is not set to true. | +| CookieWithoutHttpOnly.go:128:2:128:8 | session | Cookie attribute 'HttpOnly' is not set to true. | +| CookieWithoutHttpOnly.go:141:2:141:8 | session | Cookie attribute 'HttpOnly' is not set to true. | +| CookieWithoutHttpOnly.go:152:2:152:8 | session | Cookie attribute 'HttpOnly' is not set to true. | +| CookieWithoutHttpOnly.go:189:75:189:79 | false | Cookie attribute 'HttpOnly' is not set to true. | diff --git a/ql/test/experimental/CWE-1004/CookieWithoutHttpOnly.go b/ql/test/experimental/CWE-1004/CookieWithoutHttpOnly.go new file mode 100644 index 00000000000..cb2756c3b13 --- /dev/null +++ b/ql/test/experimental/CWE-1004/CookieWithoutHttpOnly.go @@ -0,0 +1,194 @@ +package main + +import ( + "net/http" + "github.com/gin-gonic/gin" + "github.com/gorilla/sessions" +) + +func handler1(w http.ResponseWriter, r *http.Request) { + c := http.Cookie{ + Name: "session", + Value: "secret", + } + http.SetCookie(w, &c) // BAD: HttpOnly set to false by default +} + +func handler2(w http.ResponseWriter, r *http.Request) { + c := http.Cookie{ + Name: "session", + Value: "secret", + HttpOnly: false, + } + http.SetCookie(w, &c) // BAD: HttpOnly explicitly set to false +} + +func handler3(w http.ResponseWriter, r *http.Request) { + c := http.Cookie{ + Name: "session", + Value: "secret", + HttpOnly: true, + } + http.SetCookie(w, &c) // GOOD: HttpOnly explicitly set to true +} + +func handler4(w http.ResponseWriter, r *http.Request) { + c := http.Cookie{ + Name: "session", + Value: "secret", + } + c.HttpOnly = true + http.SetCookie(w, &c) // GOOD: HttpOnly explicitly set to true +} + +func handler5(w http.ResponseWriter, r *http.Request) { + c := http.Cookie{ + Name: "session", + Value: "secret", + } + c.HttpOnly = false + http.SetCookie(w, &c) // BAD: HttpOnly explicitly set to false +} + +func handler6(w http.ResponseWriter, r *http.Request) { + val := false + c := http.Cookie{ + Name: "session", + Value: "secret", + HttpOnly: val, + } + http.SetCookie(w, &c) // BAD: HttpOnly explicitly set to false +} + +func handler7(w http.ResponseWriter, r *http.Request) { + val := true + c := http.Cookie{ + Name: "session", + Value: "secret", + HttpOnly: val, + } + http.SetCookie(w, &c) // GOOD: HttpOnly explicitly set to true +} + +func handler8(w http.ResponseWriter, r *http.Request) { + val := true + c := http.Cookie{ + Name: "session", + Value: "secret", + } + c.HttpOnly = val + http.SetCookie(w, &c) // GOOD: HttpOnly explicitly set to true +} + +func handler9(w http.ResponseWriter, r *http.Request) { + val := false + c := http.Cookie{ + Name: "session", + Value: "secret", + } + c.HttpOnly = val + http.SetCookie(w, &c) // BAD: HttpOnly explicitly set to false +} + +func handler10(w http.ResponseWriter, r *http.Request) { + c := http.Cookie{ + Name: "consent", + Value: "1", + } + c.HttpOnly = false + http.SetCookie(w, &c) // GOOD: Name is not auth related +} + +func handler11(w http.ResponseWriter, r *http.Request) { + name := "session" + c := http.Cookie{ + Name: name, + Value: "secret", + } + c.HttpOnly = false + http.SetCookie(w, &c) // BAD: auth related name +} + +func handler12(w http.ResponseWriter, r *http.Request) { + session := "login_name" + c := http.Cookie{ + Name: session, + Value: "secret", + } + c.HttpOnly = false + http.SetCookie(w, &c) // BAD: auth related name +} + +var store = sessions.NewCookieStore([]byte("aa")) + +func handler13(w http.ResponseWriter, r *http.Request) { + session, _ := store.Get(r, "session-name") + session.Values["foo"] = "secret" + + session.Save(r, w) // BAD: Default options are set (false) +} + +func handler14(w http.ResponseWriter, r *http.Request) { + httpOnly := false + session, _ := store.Get(r, "session-name") + session.Values["foo"] = "secret" + + session.Options = &sessions.Options{ + MaxAge: -1, + HttpOnly: httpOnly, + } + + session.Save(r, w) // BAD: Explicitly set to false +} + +func handler15(w http.ResponseWriter, r *http.Request) { + session, _ := store.Get(r, "session-name") + session.Values["foo"] = "secret" + + session.Options = &sessions.Options{ + MaxAge: -1, + } + + session.Save(r, w) // BAD: default (false) is used +} + +func handler16(w http.ResponseWriter, r *http.Request) { + httpOnly := true + session, _ := store.Get(r, "session-name") + session.Values["foo"] = "secret" + + session.Options = &sessions.Options{ + MaxAge: -1, + HttpOnly: httpOnly, + } + + session.Save(r, w) // GOOD: value is true +} + +func handler17(w http.ResponseWriter, r *http.Request, httpOnly bool) { + session, _ := store.Get(r, "session-name") + session.Values["foo"] = "secret" + + session.Options = &sessions.Options{ + MaxAge: -1, + HttpOnly: httpOnly, + } + + session.Save(r, w) // GOOD: value is unknown +} + +func main() { + + router := gin.Default() + + router.GET("/cookie", func(c *gin.Context) { + + _, err := c.Cookie("session") + + if err != nil { + c.SetCookie("session", "test", 3600, "/", "localhost", false, false) // BAD: httpOnly set to false + } + }) + + router.Run() +} diff --git a/ql/test/experimental/CWE-1004/CookieWithoutHttpOnly.qlref b/ql/test/experimental/CWE-1004/CookieWithoutHttpOnly.qlref new file mode 100644 index 00000000000..ca6a153038c --- /dev/null +++ b/ql/test/experimental/CWE-1004/CookieWithoutHttpOnly.qlref @@ -0,0 +1 @@ +experimental/CWE-1004/CookieWithoutHttpOnly.ql diff --git a/ql/test/experimental/CWE-1004/go.mod b/ql/test/experimental/CWE-1004/go.mod new file mode 100644 index 00000000000..a35c003a4ba --- /dev/null +++ b/ql/test/experimental/CWE-1004/go.mod @@ -0,0 +1,8 @@ +module example.com/m + +go 1.14 + +require ( + github.com/gin-gonic/gin v1.6.2 + github.com/gorilla/sessions v1.2.1 + ) diff --git a/ql/test/experimental/CWE-1004/vendor/github.com/gin-gonic/gin/LICENSE b/ql/test/experimental/CWE-1004/vendor/github.com/gin-gonic/gin/LICENSE new file mode 100644 index 00000000000..1ff7f370605 --- /dev/null +++ b/ql/test/experimental/CWE-1004/vendor/github.com/gin-gonic/gin/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2014 Manuel Martínez-Almeida + +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/CWE-1004/vendor/github.com/gin-gonic/gin/binding/stub.go b/ql/test/experimental/CWE-1004/vendor/github.com/gin-gonic/gin/binding/stub.go new file mode 100644 index 00000000000..43fd634edcd --- /dev/null +++ b/ql/test/experimental/CWE-1004/vendor/github.com/gin-gonic/gin/binding/stub.go @@ -0,0 +1,12 @@ +// Code generated by depstubber. DO NOT EDIT. +// This is a simple stub for github.com/gin-gonic/gin/binding, strictly for use in testing. + +// See the LICENSE file for information about the licensing of the original library. +// Source: github.com/gin-gonic/gin/binding (exports: ; functions: YAML) + +// Package binding is a stub of github.com/gin-gonic/gin/binding, generated by depstubber. +package binding + +import () + +var YAML interface{} = nil diff --git a/ql/test/experimental/CWE-1004/vendor/github.com/gin-gonic/gin/stub.go b/ql/test/experimental/CWE-1004/vendor/github.com/gin-gonic/gin/stub.go new file mode 100644 index 00000000000..eb68095e53e --- /dev/null +++ b/ql/test/experimental/CWE-1004/vendor/github.com/gin-gonic/gin/stub.go @@ -0,0 +1,500 @@ +// Code generated by depstubber. DO NOT EDIT. +// This is a simple stub for github.com/gin-gonic/gin, strictly for use in testing. + +// See the LICENSE file for information about the licensing of the original library. +// Source: github.com/gin-gonic/gin (exports: Context; functions: ) + +// Package gin is a stub of github.com/gin-gonic/gin, generated by depstubber. +package gin + +import ( + bufio "bufio" + io "io" + multipart "mime/multipart" + net "net" + http "net/http" + sync "sync" + time "time" +) + +type Context struct { + Request *http.Request + Writer ResponseWriter + Params Params + KeysMutex *sync.RWMutex + Keys map[string]interface{} + Errors interface{} + Accepted []string +} + +func (_ *Context) Abort() {} + +func (_ *Context) AbortWithError(_ int, _ interface { + Error() string +}) *Error { + return nil +} + +func (_ *Context) AbortWithStatus(_ int) {} + +func (_ *Context) AbortWithStatusJSON(_ int, _ interface{}) {} + +func (_ *Context) AsciiJSON(_ int, _ interface{}) {} + +func (_ *Context) Bind(_ interface{}) interface { + Error() string +} { + return nil +} + +func (_ *Context) BindHeader(_ interface{}) interface { + Error() string +} { + return nil +} + +func (_ *Context) BindJSON(_ interface{}) interface { + Error() string +} { + return nil +} + +func (_ *Context) BindQuery(_ interface{}) interface { + Error() string +} { + return nil +} + +func (_ *Context) BindUri(_ interface{}) interface { + Error() string +} { + return nil +} + +func (_ *Context) BindWith(_ interface{}, _ interface{}) interface { + Error() string +} { + return nil +} + +func (_ *Context) BindXML(_ interface{}) interface { + Error() string +} { + return nil +} + +func (_ *Context) BindYAML(_ interface{}) interface { + Error() string +} { + return nil +} + +func (_ *Context) ClientIP() string { + return "" +} + +func (_ *Context) ContentType() string { + return "" +} + +func (_ *Context) Cookie(_ string) (string, interface { + Error() string +}) { + return "", nil +} + +func (_ *Context) Copy() *Context { + return nil +} + +func (_ *Context) Data(_ int, _ string, _ []uint8) {} + +func (_ *Context) DataFromReader(_ int, _ int64, _ string, _ io.Reader, _ map[string]string) {} + +func (_ *Context) Deadline() (time.Time, bool) { + return time.Time{}, false +} + +func (_ *Context) DefaultPostForm(_ string, _ string) string { + return "" +} + +func (_ *Context) DefaultQuery(_ string, _ string) string { + return "" +} + +func (_ *Context) Done() <-chan struct{} { + return nil +} + +func (_ *Context) Err() interface { + Error() string +} { + return nil +} + +func (_ *Context) Error(_ interface { + Error() string +}) *Error { + return nil +} + +func (_ *Context) File(_ string) {} + +func (_ *Context) FileAttachment(_ string, _ string) {} + +func (_ *Context) FileFromFS(_ string, _ http.FileSystem) {} + +func (_ *Context) FormFile(_ string) (*multipart.FileHeader, interface { + Error() string +}) { + return nil, nil +} + +func (_ *Context) FullPath() string { + return "" +} + +func (_ *Context) Get(_ string) (interface{}, bool) { + return nil, false +} + +func (_ *Context) GetBool(_ string) bool { + return false +} + +func (_ *Context) GetDuration(_ string) time.Duration { + return 0 +} + +func (_ *Context) GetFloat64(_ string) float64 { + return 0 +} + +func (_ *Context) GetHeader(_ string) string { + return "" +} + +func (_ *Context) GetInt(_ string) int { + return 0 +} + +func (_ *Context) GetInt64(_ string) int64 { + return 0 +} + +func (_ *Context) GetPostForm(_ string) (string, bool) { + return "", false +} + +func (_ *Context) GetPostFormArray(_ string) ([]string, bool) { + return nil, false +} + +func (_ *Context) GetPostFormMap(_ string) (map[string]string, bool) { + return nil, false +} + +func (_ *Context) GetQuery(_ string) (string, bool) { + return "", false +} + +func (_ *Context) GetQueryArray(_ string) ([]string, bool) { + return nil, false +} + +func (_ *Context) GetQueryMap(_ string) (map[string]string, bool) { + return nil, false +} + +func (_ *Context) GetRawData() ([]uint8, interface { + Error() string +}) { + return nil, nil +} + +func (_ *Context) GetString(_ string) string { + return "" +} + +func (_ *Context) GetStringMap(_ string) map[string]interface{} { + return nil +} + +func (_ *Context) GetStringMapString(_ string) map[string]string { + return nil +} + +func (_ *Context) GetStringMapStringSlice(_ string) map[string][]string { + return nil +} + +func (_ *Context) GetStringSlice(_ string) []string { + return nil +} + +func (_ *Context) GetTime(_ string) time.Time { + return time.Time{} +} + +func (_ *Context) HTML(_ int, _ string, _ interface{}) {} + +func (_ *Context) Handler() HandlerFunc { + return nil +} + +func (_ *Context) HandlerName() string { + return "" +} + +func (_ *Context) HandlerNames() []string { + return nil +} + +func (_ *Context) Header(_ string, _ string) {} + +func (_ *Context) IndentedJSON(_ int, _ interface{}) {} + +func (_ *Context) IsAborted() bool { + return false +} + +func (_ *Context) IsWebsocket() bool { + return false +} + +func (_ *Context) JSON(_ int, _ interface{}) {} + +func (_ *Context) JSONP(_ int, _ interface{}) {} + +func (_ *Context) MultipartForm() (*multipart.Form, interface { + Error() string +}) { + return nil, nil +} + +func (_ *Context) MustBindWith(_ interface{}, _ interface{}) interface { + Error() string +} { + return nil +} + +func (_ *Context) MustGet(_ string) interface{} { + return nil +} + +func (_ *Context) Negotiate(_ int, _ Negotiate) {} + +func (_ *Context) NegotiateFormat(_ ...string) string { + return "" +} + +func (_ *Context) Next() {} + +func (_ *Context) Param(_ string) string { + return "" +} + +func (_ *Context) PostForm(_ string) string { + return "" +} + +func (_ *Context) PostFormArray(_ string) []string { + return nil +} + +func (_ *Context) PostFormMap(_ string) map[string]string { + return nil +} + +func (_ *Context) ProtoBuf(_ int, _ interface{}) {} + +func (_ *Context) PureJSON(_ int, _ interface{}) {} + +func (_ *Context) Query(_ string) string { + return "" +} + +func (_ *Context) QueryArray(_ string) []string { + return nil +} + +func (_ *Context) QueryMap(_ string) map[string]string { + return nil +} + +func (_ *Context) Redirect(_ int, _ string) {} + +func (_ *Context) Render(_ int, _ interface{}) {} + +func (_ *Context) SSEvent(_ string, _ interface{}) {} + +func (_ *Context) SaveUploadedFile(_ *multipart.FileHeader, _ string) interface { + Error() string +} { + return nil +} + +func (_ *Context) SecureJSON(_ int, _ interface{}) {} + +func (_ *Context) Set(_ string, _ interface{}) {} + +func (_ *Context) SetAccepted(_ ...string) {} + +func (_ *Context) SetCookie(_ string, _ string, _ int, _ string, _ string, _ bool, _ bool) {} + +func (_ *Context) SetSameSite(_ http.SameSite) {} + +func (_ *Context) ShouldBind(_ interface{}) interface { + Error() string +} { + return nil +} + +func (_ *Context) ShouldBindBodyWith(_ interface{}, _ interface{}) interface { + Error() string +} { + return nil +} + +func (_ *Context) ShouldBindHeader(_ interface{}) interface { + Error() string +} { + return nil +} + +func (_ *Context) ShouldBindJSON(_ interface{}) interface { + Error() string +} { + return nil +} + +func (_ *Context) ShouldBindQuery(_ interface{}) interface { + Error() string +} { + return nil +} + +func (_ *Context) ShouldBindUri(_ interface{}) interface { + Error() string +} { + return nil +} + +func (_ *Context) ShouldBindWith(_ interface{}, _ interface{}) interface { + Error() string +} { + return nil +} + +func (_ *Context) ShouldBindXML(_ interface{}) interface { + Error() string +} { + return nil +} + +func (_ *Context) ShouldBindYAML(_ interface{}) interface { + Error() string +} { + return nil +} + +func (_ *Context) Status(_ int) {} + +func (_ *Context) Stream(_ func(io.Writer) bool) bool { + return false +} + +func (_ *Context) String(_ int, _ string, _ ...interface{}) {} + +func (_ *Context) Value(_ interface{}) interface{} { + return nil +} + +func (_ *Context) XML(_ int, _ interface{}) {} + +func (_ *Context) YAML(_ int, _ interface{}) {} + +type Error struct { + Err interface { + Error() string + } + Type ErrorType + Meta interface{} +} + +func (_ Error) Error() string { + return "" +} + +func (_ *Error) IsType(_ ErrorType) bool { + return false +} + +func (_ *Error) JSON() interface{} { + return nil +} + +func (_ *Error) MarshalJSON() ([]uint8, interface { + Error() string +}) { + return nil, nil +} + +func (_ *Error) SetMeta(_ interface{}) *Error { + return nil +} + +func (_ *Error) SetType(_ ErrorType) *Error { + return nil +} + +type ErrorType uint64 + +type HandlerFunc func(*Context) + +type Negotiate struct { + Offered []string + HTMLName string + HTMLData interface{} + JSONData interface{} + XMLData interface{} + YAMLData interface{} + Data interface{} +} + +type Param struct { + Key string + Value string +} + +type Params []Param + +func (_ Params) ByName(_ string) string { + return "" +} + +func (_ Params) Get(_ string) (string, bool) { + return "", false +} + +type ResponseWriter interface { + CloseNotify() <-chan bool + Flush() + Header() http.Header + Hijack() (net.Conn, *bufio.ReadWriter, interface { + Error() string + }) + Pusher() http.Pusher + Size() int + Status() int + Write(_ []uint8) (int, interface { + Error() string + }) + WriteHeader(_ int) + WriteHeaderNow() + WriteString(_ string) (int, interface { + Error() string + }) + Written() bool +} diff --git a/ql/test/experimental/CWE-1004/vendor/github.com/gorilla/sessions/stub.go b/ql/test/experimental/CWE-1004/vendor/github.com/gorilla/sessions/stub.go new file mode 100644 index 00000000000..2ebc3858163 --- /dev/null +++ b/ql/test/experimental/CWE-1004/vendor/github.com/gorilla/sessions/stub.go @@ -0,0 +1,75 @@ +// Code generated by depstubber. DO NOT EDIT. +// This is a simple stub for github.com/gorilla/sessions, strictly for use in testing. + +// See the LICENSE file for information about the licensing of the original library. +// Source: github.com/gorilla/sessions (exports: CookieStore; functions: NewCookieStore) + +// Package sessions is a stub of github.com/gorilla/sessions, generated by depstubber. +package sessions + +import ( + http "net/http" +) + +type CookieStore struct { + Codecs []interface{} + Options *Options +} + +func (_ *CookieStore) Get(_ *http.Request, _ string) (*Session, error) { + return nil, nil +} + +func (_ *CookieStore) MaxAge(_ int) {} + +func (_ *CookieStore) New(_ *http.Request, _ string) (*Session, error) { + return nil, nil +} + +func (_ *CookieStore) Save(_ *http.Request, _ http.ResponseWriter, _ *Session) error { + return nil +} + +func NewCookieStore(_ ...[]byte) *CookieStore { + return nil +} + +type Options struct { + Path string + Domain string + MaxAge int + Secure bool + HttpOnly bool + SameSite http.SameSite +} + +type Session struct { + ID string + Values map[interface{}]interface{} + Options *Options + IsNew bool +} + +func (_ *Session) AddFlash(_ interface{}, _ ...string) {} + +func (_ *Session) Flashes(_ ...string) []interface{} { + return nil +} + +func (_ *Session) Name() string { + return "" +} + +func (_ *Session) Save(_ *http.Request, _ http.ResponseWriter) error { + return nil +} + +func (_ *Session) Store() Store { + return nil +} + +type Store interface { + Get(_ *http.Request, _ string) (*Session, error) + New(_ *http.Request, _ string) (*Session, error) + Save(_ *http.Request, _ http.ResponseWriter, _ *Session) error +} diff --git a/ql/test/experimental/CWE-1004/vendor/modules.txt b/ql/test/experimental/CWE-1004/vendor/modules.txt new file mode 100644 index 00000000000..659b82c1e3d --- /dev/null +++ b/ql/test/experimental/CWE-1004/vendor/modules.txt @@ -0,0 +1,6 @@ +# github.com/gin-gonic/gin v1.6.2 +## explicit +github.com/gin-gonic/gin +# github.com/gorilla/sessions v1.2.1 +## explicit +github.com/gorilla/sessions