From bd1ddc177e2da2a8f5e47c0d72068dabd1c5eec6 Mon Sep 17 00:00:00 2001 From: Porcupiney Hairs Date: Tue, 31 May 2022 01:53:04 +0530 Subject: [PATCH 01/11] Golang : Add query to detect JWT signing vulnerabilities Supersedes github/codeql-go#705 --- .../experimental/CWE-321/HardcodedKeys.qhelp | 50 ++ .../src/experimental/CWE-321/HardcodedKeys.ql | 18 + .../experimental/CWE-321/HardcodedKeysBad.go | 9 + .../experimental/CWE-321/HardcodedKeysGood.go | 23 + .../experimental/CWE-321/HardcodedKeysLib.qll | 271 +++++++ .../CWE-321/HardcodedKeys.expected | 68 ++ .../experimental/CWE-321/HardcodedKeys.qlref | 1 + .../experimental/CWE-321/HardcodedKeysBad.go | 20 + .../experimental/CWE-321/HardcodedKeysGood.go | 38 + go/ql/test/experimental/CWE-321/go.mod | 41 ++ go/ql/test/experimental/CWE-321/main.go | 127 ++++ .../github.com/appleboy/gin-jwt/v2/stub.go | 93 +++ .../github.com/cristalhq/jwt/v3/stub.go | 26 + .../vendor/github.com/gin-gonic/gin/stub.go | 681 ++++++++++++++++++ .../github.com/go-kit/kit/auth/jwt/stub.go | 12 + .../github.com/golang-jwt/jwt/v4/stub.go | 328 +++++++++ .../github.com/lestrrat/go-jwx/jwk/stub.go | 39 + .../github.com/square/go-jose/v3/stub.go | 219 ++++++ .../vendor/gopkg.in/square/go-jose.v2/stub.go | 219 ++++++ .../experimental/CWE-321/vendor/modules.txt | 96 +++ 20 files changed, 2379 insertions(+) create mode 100644 go/ql/src/experimental/CWE-321/HardcodedKeys.qhelp create mode 100644 go/ql/src/experimental/CWE-321/HardcodedKeys.ql create mode 100644 go/ql/src/experimental/CWE-321/HardcodedKeysBad.go create mode 100644 go/ql/src/experimental/CWE-321/HardcodedKeysGood.go create mode 100644 go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll create mode 100644 go/ql/test/experimental/CWE-321/HardcodedKeys.expected create mode 100644 go/ql/test/experimental/CWE-321/HardcodedKeys.qlref create mode 100644 go/ql/test/experimental/CWE-321/HardcodedKeysBad.go create mode 100644 go/ql/test/experimental/CWE-321/HardcodedKeysGood.go create mode 100644 go/ql/test/experimental/CWE-321/go.mod create mode 100644 go/ql/test/experimental/CWE-321/main.go create mode 100644 go/ql/test/experimental/CWE-321/vendor/github.com/appleboy/gin-jwt/v2/stub.go create mode 100644 go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/stub.go create mode 100644 go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/stub.go create mode 100644 go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/auth/jwt/stub.go create mode 100644 go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/stub.go create mode 100644 go/ql/test/experimental/CWE-321/vendor/github.com/lestrrat/go-jwx/jwk/stub.go create mode 100644 go/ql/test/experimental/CWE-321/vendor/github.com/square/go-jose/v3/stub.go create mode 100644 go/ql/test/experimental/CWE-321/vendor/gopkg.in/square/go-jose.v2/stub.go create mode 100644 go/ql/test/experimental/CWE-321/vendor/modules.txt diff --git a/go/ql/src/experimental/CWE-321/HardcodedKeys.qhelp b/go/ql/src/experimental/CWE-321/HardcodedKeys.qhelp new file mode 100644 index 000000000000..a02812296a4b --- /dev/null +++ b/go/ql/src/experimental/CWE-321/HardcodedKeys.qhelp @@ -0,0 +1,50 @@ + + + +

+ A JSON Web Token (JWT) is used for authenticating and managing users in an application. +

+

+ Using a hard-coded secret key for signing JWT tokens in open source projects + can leave the application using the token vulnerable to authentication bypasses. +

+ +

+ A JWT token is safe for enforcing authentication and access control as long as it can't be forged by a malicious actor. However, when a project exposes this secret publicly, these seemingly unforgeable tokens can now be easily forged. + Since the authentication as well as access control is typically enforced through these JWT tokens, an attacker armed with the secret can create a valid authentication token for any user and may even gain access to other privileged parts of the application. +

+ +
+ + +

+ Generating a crytograhically secure secret key during application initialization and using this generated key for future JWT signing requests can prevent this vulnerability. +

+ +
+ + +

+ The following code uses a hard-coded string as a secret for signing the tokens. In this case, an attacker can very easily forge a token by using the hard-coded secret. +

+ + + +
+ + +

+ In the following case, the application uses a programatically generated string as a secret for signing the tokens. In this case, since the secret can't be predicted, the code is secure. A function like `GenerateCryptoString` can be run to generate a secure secret key at the time of application installation/initialization. This generated key can then be used for all future signing requests. +

+ + + +
+ +
  • + CVE-2022-0664: + Use of Hard-coded Cryptographic Key in Go github.com/gravitl/netmaker prior to 0.8.5,0.9.4,0.10.0,0.10.1. +
  • +
    + +
    \ No newline at end of file diff --git a/go/ql/src/experimental/CWE-321/HardcodedKeys.ql b/go/ql/src/experimental/CWE-321/HardcodedKeys.ql new file mode 100644 index 000000000000..06dacfcac278 --- /dev/null +++ b/go/ql/src/experimental/CWE-321/HardcodedKeys.ql @@ -0,0 +1,18 @@ +/** + * @name Use of a hardcoded key for signing JWT + * @description Using a fixed hardcoded key for signing JWT's can allow an attacker to compromise security. + * @kind path-problem + * @problem.severity error + * @id go/hardcoded-key + * @tags security + * external/cwe/cwe-321 + */ + +import go +import HardcodedKeysLib +import DataFlow::PathGraph + +from HardcodedKeys::Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink +where cfg.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "$@ is used to sign a JWT token.", source.getNode(), + "Hardcoded String" diff --git a/go/ql/src/experimental/CWE-321/HardcodedKeysBad.go b/go/ql/src/experimental/CWE-321/HardcodedKeysBad.go new file mode 100644 index 000000000000..e0bb2225092f --- /dev/null +++ b/go/ql/src/experimental/CWE-321/HardcodedKeysBad.go @@ -0,0 +1,9 @@ +mySigningKey := []byte("AllYourBase") + +claims := &jwt.RegisteredClaims{ + ExpiresAt: jwt.NewNumericDate(time.Unix(1516239022, 0)), + Issuer: "test", +} + +token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) +ss, err := token.SignedString(mySigningKey) diff --git a/go/ql/src/experimental/CWE-321/HardcodedKeysGood.go b/go/ql/src/experimental/CWE-321/HardcodedKeysGood.go new file mode 100644 index 000000000000..06c09fd34b74 --- /dev/null +++ b/go/ql/src/experimental/CWE-321/HardcodedKeysGood.go @@ -0,0 +1,23 @@ +func GenerateCryptoString(n int) (string, error) { + const chars = "123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-" + ret := make([]byte, n) + for i := range ret { + num, err := crand.Int(crand.Reader, big.NewInt(int64(len(chars)))) + if err != nil { + return "", err + } + ret[i] = chars[num.Int64()] + } + return string(ret), nil +} + +mySigningKey := GenerateCryptoString(64) + + +claims := &jwt.RegisteredClaims{ + ExpiresAt: jwt.NewNumericDate(time.Unix(1516239022, 0)), + Issuer: "test", +} + +token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) +ss, err := token.SignedString(mySigningKey) diff --git a/go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll b/go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll new file mode 100644 index 000000000000..30bada97aa30 --- /dev/null +++ b/go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll @@ -0,0 +1,271 @@ +/** + * Provides default sources, sinks and sanitizers for reasoning about + * JWT token signing vulnerabilities as well as extension points + * for adding your own. + */ + +import go +import StringOps +import DataFlow::PathGraph + +/** + * Provides default sources, sinks and sanitizers for reasoning about + * JWT token signing vulnerabilities as well as extension points + * for adding your own. + */ +module HardcodedKeys { + /** + * A data flow source for JWT token signing vulnerabilities. + */ + abstract class Source extends DataFlow::Node { } + + /** + * A data flow sink for JWT token signing vulnerabilities. + */ + abstract class Sink extends DataFlow::Node { } + + /** + * A sanitizer for JWT token signing vulnerabilities. + */ + abstract class Sanitizer extends DataFlow::Node { } + + /** + * A sanitizer guard for JWT token signing vulnerabilities. + */ + abstract class SanitizerGuard extends DataFlow::BarrierGuard { } + + private predicate isTestCode(Expr e) { + e.getFile().getAbsolutePath().toLowerCase().matches("%test%") and + not e.getFile().getAbsolutePath().toLowerCase().matches("%ql/test%") + } + + private predicate isDemoCode(Expr e) { + e.getFile().getAbsolutePath().toLowerCase().matches(["%mock%", "%demo%", "%example%"]) + } + + /** + * A hardcoded string literal as a source for JWT token signing vulnerabilities. + */ + class HardcodedStringSource extends Source { + HardcodedStringSource() { + this.asExpr() instanceof StringLit and + not (isTestCode(this.asExpr()) or isDemoCode(this.asExpr())) + } + } + + /** + * An expression used to sign JWT tokens as a sink for JWT token signing vulnerabilities. + */ + private class GolangJwtSign extends Sink { + GolangJwtSign() { + exists(string pkg | + pkg = + [ + "github.com/golang-jwt/jwt/v4", "github.com/dgrijalva/jwt-go", + "github.com/form3tech-oss/jwt-go", "github.com/ory/fosite/token/jwt" + ] + | + ( + exists(DataFlow::MethodCallNode m | + // Models the `SignedString` method + // `func (t *Token) SignedString(key interface{}) (string, error)` + m.getTarget().hasQualifiedName(pkg, "Token", "SignedString") + | + this = m.getArgument(0) + ) + or + exists(DataFlow::MethodCallNode m | + // Model the `Sign` method of the `SigningMethod` interface + // type SigningMethod interface { + // Verify(signingString, signature string, key interface{}) error + // Sign(signingString string, key interface{}) (string, error) + // Alg() string + // } + m.getTarget().hasQualifiedName(pkg, "SigningMethod", "Sign") + | + this = m.getArgument(1) + ) + ) + ) + } + } + + private class GinJwtSign extends Sink { + GinJwtSign() { + exists(Field f | + // https://pkg.go.dev/github.com/appleboy/gin-jwt/v2#GinJWTMiddleware + f.hasQualifiedName("github.com/appleboy/gin-jwt/v2", "GinJWTMiddleware", "Key") and + f.getAWrite().getRhs() = this + ) + } + } + + private class SquareJoseKey extends Sink { + SquareJoseKey() { + exists(Field f, string pkg | + // type Recipient struct { + // Algorithm KeyAlgorithm + // Key interface{} + // KeyID string + // PBES2Count int + // PBES2Salt []byte + // } + // type SigningKey struct { + // Algorithm SignatureAlgorithm + // Key interface{} + // } + f.hasQualifiedName(pkg, ["Recipient", "SigningKey"], "Key") and + f.getAWrite().getRhs() = this + | + pkg = ["github.com/square/go-jose/v3", "gopkg.in/square/go-jose.v2"] + ) + } + } + + private class CrystalHqJwtSigner extends Sink { + CrystalHqJwtSigner() { + exists(DataFlow::CallNode m | + // `func NewSignerHS(alg Algorithm, key []byte) (Signer, error)` + m.getTarget().hasQualifiedName("github.com/cristalhq/jwt/v3", "NewSignerHS") + | + this = m.getArgument(1) + ) + } + } + + private class GoKitJwt extends Sink { + GoKitJwt() { + exists(DataFlow::CallNode m | + // `func NewSigner(kid string, key []byte, method jwt.SigningMethod, claims jwt.Claims) endpoint.Middleware` + m.getTarget().hasQualifiedName("github.com/go-kit/kit/auth/jwt", "NewSigner") + | + this = m.getArgument(1) + ) + } + } + + private class LestrratJwk extends Sink { + LestrratJwk() { + exists(DataFlow::CallNode m, string pkg | + pkg.matches([ + "github.com/lestrrat-go/jwx", "github.com/lestrrat/go-jwx/jwk", + "github.com/lestrrat-go/jwx%/jwk" + ]) and + // `func New(key interface{}) (Key, error)` + m.getTarget().hasQualifiedName(pkg, "New") + | + this = m.getArgument(0) + ) + } + } + + /** + * Mark any comparision expression where any operand is tainted as a + * sanitizer for all instances of the taint + */ + private class CompareExprSanitizer extends Sanitizer { + CompareExprSanitizer() { + exists(BinaryExpr c | + c.getAnOperand().getGlobalValueNumber() = this.asExpr().getGlobalValueNumber() + ) + } + } + + /** Mark an empty string returned with an error as a sanitizer */ + class EmptyErrorSanitizer extends Sanitizer { + EmptyErrorSanitizer() { + exists(ReturnStmt r, DataFlow::CallNode c | + c.getTarget().hasQualifiedName("errors", "New") and + r.getNumChild() > 1 and + r.getAChild() = c.getAResult().getASuccessor*().asExpr() and + r.getAChild() = this.asExpr() + ) + } + } + + /** Mark any formatting string call as a sanitizer */ + class FormattingSanitizer extends Sanitizer { + FormattingSanitizer() { exists(Formatting::StringFormatCall s | s.getAResult() = this) } + } + + /** + * Mark any taint arising from a read on a tainted slice with a random index as a + * sanitizer for all instances of the taint + */ + private class RandSliceSanitizer extends Sanitizer { + RandSliceSanitizer() { + exists(DataFlow::CallNode randint, string name, DataFlow::ElementReadNode r | + ( + randint.getTarget().hasQualifiedName("math/rand", name) or + randint.getTarget().(Method).hasQualifiedName("math/rand", "Rand", name) + ) and + name = + [ + "ExpFloat64", "Float32", "Float64", "Int", "Int31", "Int31n", "Int63", "Int63n", "Intn", + "NormFloat64", "Uint32", "Uint64" + ] and + r.reads(this, randint.getAResult().getASuccessor*()) + ) + or + // Sanitize flows like this: + // func GenerateCryptoString(n int) (string, error) { + // const chars = "123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-" + // ret := make([]byte, n) + // for i := range ret { + // num, err := crand.Int(crand.Reader, big.NewInt(int64(len(chars)))) + // if err != nil { + // return "", err + // } + // ret[i] = chars[num.Int64()] + // } + // return string(ret), nil + // } + exists( + DataFlow::CallNode randint, DataFlow::MethodCallNode bigint, DataFlow::ElementReadNode r + | + randint.getTarget().hasQualifiedName("crypto/rand", "Int") and + bigint.getTarget().hasQualifiedName("math/big", "Int", "Int64") and + bigint.getReceiver() = randint.getResult(0).getASuccessor*() and + r.reads(this, bigint.getAResult().getASuccessor*()) + ) + or + // Sanitize flows like : + // func GenerateRandomString(size int) string { + // var bytes = make([]byte, size) + // rand.Read(bytes) + // for i, x := range bytes { + // bytes[i] = characters[x%byte(len(characters))] + // } + // return string(bytes) + // } + exists(DataFlow::CallNode randread, DataFlow::Node rand, DataFlow::ElementReadNode r | + randread.getTarget().hasQualifiedName("crypto/rand", "Read") and + TaintTracking::localTaint(randread.getArgument(0).getAPredecessor*().getASuccessor*(), rand) and + ( + exists(ModExpr e | e.getAnOperand() = rand.asExpr() | + r.reads(this, e.getGlobalValueNumber().getANode()) + ) + or + r.reads(this.getAPredecessor*(), rand) + ) + ) + } + } + + /** + * A configuration depicting taint flow for studying JWT token signing vulnerabilities. + */ + class Configuration extends TaintTracking::Configuration { + Configuration() { this = "Hard-coded JWT Signing Key" } + + override predicate isSource(DataFlow::Node source) { source instanceof Source } + + override predicate isSink(DataFlow::Node sink) { sink instanceof Sink } + + override predicate isSanitizer(DataFlow::Node sanitizer) { sanitizer instanceof Sanitizer } + + override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { + guard instanceof SanitizerGuard + } + } +} diff --git a/go/ql/test/experimental/CWE-321/HardcodedKeys.expected b/go/ql/test/experimental/CWE-321/HardcodedKeys.expected new file mode 100644 index 000000000000..b50e78b6ebf0 --- /dev/null +++ b/go/ql/test/experimental/CWE-321/HardcodedKeys.expected @@ -0,0 +1,68 @@ +edges +| HardcodedKeysBad.go:11:18:11:38 | type conversion : string | HardcodedKeysBad.go:19:28:19:39 | mySigningKey | +| HardcodedKeysBad.go:11:25:11:37 | "AllYourBase" : string | HardcodedKeysBad.go:11:18:11:38 | type conversion : string | +| main.go:25:18:25:31 | type conversion : string | main.go:34:28:34:39 | mySigningKey | +| main.go:25:25:25:30 | "key1" : string | main.go:25:18:25:31 | type conversion : string | +| main.go:42:23:42:28 | "key2" : string | main.go:42:16:42:29 | type conversion | +| main.go:60:9:60:22 | type conversion : string | main.go:61:44:61:46 | key | +| main.go:60:16:60:21 | `key3` : string | main.go:60:9:60:22 | type conversion : string | +| main.go:65:9:65:22 | type conversion : string | main.go:66:66:66:68 | key | +| main.go:65:16:65:21 | "key4" : string | main.go:65:9:65:22 | type conversion : string | +| main.go:69:10:69:23 | type conversion : string | main.go:74:15:74:18 | key2 | +| main.go:69:17:69:22 | "key5" : string | main.go:69:10:69:23 | type conversion : string | +| main.go:80:9:80:22 | type conversion : string | main.go:84:41:84:43 | key | +| main.go:80:16:80:21 | "key6" : string | main.go:80:9:80:22 | type conversion : string | +| main.go:89:10:89:23 | type conversion : string | main.go:91:66:91:69 | key2 | +| main.go:89:17:89:22 | "key7" : string | main.go:89:10:89:23 | type conversion : string | +| main.go:97:9:97:22 | type conversion : string | main.go:103:30:103:32 | key | +| main.go:97:16:97:21 | "key8" : string | main.go:97:9:97:22 | type conversion : string | +| main.go:107:15:107:28 | type conversion : string | main.go:108:16:108:24 | sharedKey | +| main.go:107:22:107:27 | "key9" : string | main.go:107:15:107:28 | type conversion : string | +| main.go:111:23:111:37 | type conversion : string | main.go:114:16:114:30 | sharedKeyglobal | +| main.go:111:30:111:36 | "key10" : string | main.go:111:23:111:37 | type conversion : string | +nodes +| HardcodedKeysBad.go:11:18:11:38 | type conversion : string | semmle.label | type conversion : string | +| HardcodedKeysBad.go:11:25:11:37 | "AllYourBase" : string | semmle.label | "AllYourBase" : string | +| HardcodedKeysBad.go:19:28:19:39 | mySigningKey | semmle.label | mySigningKey | +| main.go:25:18:25:31 | type conversion : string | semmle.label | type conversion : string | +| main.go:25:25:25:30 | "key1" : string | semmle.label | "key1" : string | +| main.go:34:28:34:39 | mySigningKey | semmle.label | mySigningKey | +| main.go:42:16:42:29 | type conversion | semmle.label | type conversion | +| main.go:42:23:42:28 | "key2" : string | semmle.label | "key2" : string | +| main.go:60:9:60:22 | type conversion : string | semmle.label | type conversion : string | +| main.go:60:16:60:21 | `key3` : string | semmle.label | `key3` : string | +| main.go:61:44:61:46 | key | semmle.label | key | +| main.go:65:9:65:22 | type conversion : string | semmle.label | type conversion : string | +| main.go:65:16:65:21 | "key4" : string | semmle.label | "key4" : string | +| main.go:66:66:66:68 | key | semmle.label | key | +| main.go:69:10:69:23 | type conversion : string | semmle.label | type conversion : string | +| main.go:69:17:69:22 | "key5" : string | semmle.label | "key5" : string | +| main.go:74:15:74:18 | key2 | semmle.label | key2 | +| main.go:80:9:80:22 | type conversion : string | semmle.label | type conversion : string | +| main.go:80:16:80:21 | "key6" : string | semmle.label | "key6" : string | +| main.go:84:41:84:43 | key | semmle.label | key | +| main.go:89:10:89:23 | type conversion : string | semmle.label | type conversion : string | +| main.go:89:17:89:22 | "key7" : string | semmle.label | "key7" : string | +| main.go:91:66:91:69 | key2 | semmle.label | key2 | +| main.go:97:9:97:22 | type conversion : string | semmle.label | type conversion : string | +| main.go:97:16:97:21 | "key8" : string | semmle.label | "key8" : string | +| main.go:103:30:103:32 | key | semmle.label | key | +| main.go:107:15:107:28 | type conversion : string | semmle.label | type conversion : string | +| main.go:107:22:107:27 | "key9" : string | semmle.label | "key9" : string | +| main.go:108:16:108:24 | sharedKey | semmle.label | sharedKey | +| main.go:111:23:111:37 | type conversion : string | semmle.label | type conversion : string | +| main.go:111:30:111:36 | "key10" : string | semmle.label | "key10" : string | +| main.go:114:16:114:30 | sharedKeyglobal | semmle.label | sharedKeyglobal | +subpaths +#select +| HardcodedKeysBad.go:19:28:19:39 | mySigningKey | HardcodedKeysBad.go:11:25:11:37 | "AllYourBase" : string | HardcodedKeysBad.go:19:28:19:39 | mySigningKey | $@ is used to sign a JWT token. | HardcodedKeysBad.go:11:25:11:37 | "AllYourBase" | Hardcoded String | +| main.go:34:28:34:39 | mySigningKey | main.go:25:25:25:30 | "key1" : string | main.go:34:28:34:39 | mySigningKey | $@ is used to sign a JWT token. | main.go:25:25:25:30 | "key1" | Hardcoded String | +| main.go:42:16:42:29 | type conversion | main.go:42:23:42:28 | "key2" : string | main.go:42:16:42:29 | type conversion | $@ is used to sign a JWT token. | main.go:42:23:42:28 | "key2" | Hardcoded String | +| main.go:61:44:61:46 | key | main.go:60:16:60:21 | `key3` : string | main.go:61:44:61:46 | key | $@ is used to sign a JWT token. | main.go:60:16:60:21 | `key3` | Hardcoded String | +| main.go:66:66:66:68 | key | main.go:65:16:65:21 | "key4" : string | main.go:66:66:66:68 | key | $@ is used to sign a JWT token. | main.go:65:16:65:21 | "key4" | Hardcoded String | +| main.go:74:15:74:18 | key2 | main.go:69:17:69:22 | "key5" : string | main.go:74:15:74:18 | key2 | $@ is used to sign a JWT token. | main.go:69:17:69:22 | "key5" | Hardcoded String | +| main.go:84:41:84:43 | key | main.go:80:16:80:21 | "key6" : string | main.go:84:41:84:43 | key | $@ is used to sign a JWT token. | main.go:80:16:80:21 | "key6" | Hardcoded String | +| main.go:91:66:91:69 | key2 | main.go:89:17:89:22 | "key7" : string | main.go:91:66:91:69 | key2 | $@ is used to sign a JWT token. | main.go:89:17:89:22 | "key7" | Hardcoded String | +| main.go:103:30:103:32 | key | main.go:97:16:97:21 | "key8" : string | main.go:103:30:103:32 | key | $@ is used to sign a JWT token. | main.go:97:16:97:21 | "key8" | Hardcoded String | +| main.go:108:16:108:24 | sharedKey | main.go:107:22:107:27 | "key9" : string | main.go:108:16:108:24 | sharedKey | $@ is used to sign a JWT token. | main.go:107:22:107:27 | "key9" | Hardcoded String | +| main.go:114:16:114:30 | sharedKeyglobal | main.go:111:30:111:36 | "key10" : string | main.go:114:16:114:30 | sharedKeyglobal | $@ is used to sign a JWT token. | main.go:111:30:111:36 | "key10" | Hardcoded String | diff --git a/go/ql/test/experimental/CWE-321/HardcodedKeys.qlref b/go/ql/test/experimental/CWE-321/HardcodedKeys.qlref new file mode 100644 index 000000000000..83c71d75ae97 --- /dev/null +++ b/go/ql/test/experimental/CWE-321/HardcodedKeys.qlref @@ -0,0 +1 @@ +experimental/CWE-321/HardcodedKeys.ql \ No newline at end of file diff --git a/go/ql/test/experimental/CWE-321/HardcodedKeysBad.go b/go/ql/test/experimental/CWE-321/HardcodedKeysBad.go new file mode 100644 index 000000000000..2ffc46147f6e --- /dev/null +++ b/go/ql/test/experimental/CWE-321/HardcodedKeysBad.go @@ -0,0 +1,20 @@ +package main + +import ( + "time" + + jwt "github.com/golang-jwt/jwt/v4" +) + +func bad() (interface{}, error) { + + mySigningKey := []byte("AllYourBase") + + claims := &jwt.RegisteredClaims{ + ExpiresAt: jwt.NewNumericDate(time.Unix(1516239022, 0)), + Issuer: "test", + } + + token := jwt.NewWithClaims(nil, claims) + return token.SignedString(mySigningKey) +} diff --git a/go/ql/test/experimental/CWE-321/HardcodedKeysGood.go b/go/ql/test/experimental/CWE-321/HardcodedKeysGood.go new file mode 100644 index 000000000000..901392fec541 --- /dev/null +++ b/go/ql/test/experimental/CWE-321/HardcodedKeysGood.go @@ -0,0 +1,38 @@ +package main + +import ( + crand "crypto/rand" + "fmt" + "math/big" + "time" + + jwt "github.com/golang-jwt/jwt/v4" +) + +func GenerateCryptoString(n int) (string, error) { + const chars = "123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-" + ret := make([]byte, n) + for i := range ret { + num, err := crand.Int(crand.Reader, big.NewInt(int64(len(chars)))) + if err != nil { + return "", err + } + ret[i] = chars[num.Int64()] + } + return string(ret), nil +} + +func good() (interface{}, error) { + mySigningKey, err := GenerateCryptoString(64) + if mySigningKey == "" { + _ = fmt.Errorf("Error : %s", err) + } + + claims := &jwt.RegisteredClaims{ + ExpiresAt: jwt.NewNumericDate(time.Unix(1516239022, 0)), + Issuer: "test", + } + + token := jwt.NewWithClaims(nil, claims) + return token.SignedString(mySigningKey) +} diff --git a/go/ql/test/experimental/CWE-321/go.mod b/go/ql/test/experimental/CWE-321/go.mod new file mode 100644 index 000000000000..1f78c4037c06 --- /dev/null +++ b/go/ql/test/experimental/CWE-321/go.mod @@ -0,0 +1,41 @@ +module main + +go 1.18 + +require ( + github.com/appleboy/gin-jwt/v2 v2.8.0 + github.com/cristalhq/jwt/v3 v3.1.0 + github.com/go-kit/kit v0.12.0 + github.com/golang-jwt/jwt/v4 v4.4.1 + github.com/lestrrat/go-jwx v0.9.1 + github.com/square/go-jose/v3 v3.0.0-20200630053402-0a67ce9b0693 + gopkg.in/square/go-jose.v2 v2.6.0 +) + +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/gin-contrib/sse v0.1.0 // indirect + github.com/gin-gonic/gin v1.7.7 // indirect + github.com/go-kit/log v0.2.0 // indirect + github.com/go-logfmt/logfmt v0.5.1 // indirect + github.com/go-playground/locales v0.13.0 // indirect + github.com/go-playground/universal-translator v0.17.0 // indirect + github.com/go-playground/validator/v10 v10.4.1 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/leodido/go-urn v1.2.0 // indirect + github.com/lestrrat/go-pdebug v0.0.0-20180220043741-569c97477ae8 // indirect + github.com/mattn/go-isatty v0.0.14 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/ugorji/go/codec v1.1.7 // indirect + golang.org/x/crypto v0.0.0-20210915214749-c084706c2272 // indirect + golang.org/x/net v0.0.0-20210917221730-978cfadd31cf // indirect + golang.org/x/sys v0.0.0-20210917161153-d61c044b1678 // indirect + golang.org/x/text v0.3.7 // indirect + google.golang.org/genproto v0.0.0-20210917145530-b395a37504d4 // indirect + google.golang.org/grpc v1.40.0 // indirect + google.golang.org/protobuf v1.27.1 // indirect + gopkg.in/yaml.v2 v2.2.8 // indirect +) diff --git a/go/ql/test/experimental/CWE-321/main.go b/go/ql/test/experimental/CWE-321/main.go new file mode 100644 index 000000000000..5f2c5b6f7486 --- /dev/null +++ b/go/ql/test/experimental/CWE-321/main.go @@ -0,0 +1,127 @@ +package main + +//go:generate depstubber -vendor github.com/appleboy/gin-jwt/v2 GinJWTMiddleware New +//go:generate depstubber -vendor github.com/golang-jwt/jwt/v4 MapClaims,RegisteredClaims,SigningMethodRSA,SigningMethodHMAC,Token NewNumericDate,NewWithClaims +//go:generate depstubber -vendor github.com/gin-gonic/gin Context New +//go:generate depstubber -vendor github.com/go-kit/kit/auth/jwt "" NewSigner +//go:generate depstubber -vendor github.com/lestrrat/go-jwx/jwk "" New +//go:generate depstubber -vendor github.com/square/go-jose/v3 Recipient NewEncrypter,NewSigner +//go:generate depstubber -vendor gopkg.in/square/go-jose.v2 Recipient NewEncrypter,NewSigner +////go:generate depstubber -vendor github.com/cristalhq/jwt/v3 Signer NewSignerHS,HS256 + +import ( + "time" + + jwt "github.com/appleboy/gin-jwt/v2" + cristal "github.com/cristalhq/jwt/v3" + gokit "github.com/go-kit/kit/auth/jwt" + gjwt "github.com/golang-jwt/jwt/v4" + le "github.com/lestrrat/go-jwx/jwk" + jose_v3 "github.com/square/go-jose/v3" + jose_v2 "gopkg.in/square/go-jose.v2" +) + +func gjwtt() (interface{}, error) { + mySigningKey := []byte("key1") + + // Create the Claims + claims := &gjwt.RegisteredClaims{ + ExpiresAt: gjwt.NewNumericDate(time.Unix(1516239022, 0)), + Issuer: "test", + } + + token := gjwt.NewWithClaims(nil, claims) + return token.SignedString(mySigningKey) // BAD +} + +func gin_jwt() (interface{}, error) { + var identityKey = "id" + // authMiddleware, err := + return jwt.New(&jwt.GinJWTMiddleware{ + Realm: "test zone", + Key: []byte("key2"), // BAD + Timeout: time.Hour, + MaxRefresh: time.Hour, + IdentityKey: identityKey, + PayloadFunc: func(data interface{}) jwt.MapClaims { + return nil + }, + IdentityHandler: nil, + Authenticator: nil, + Authorizator: nil, + Unauthorized: nil, + TokenLookup: "header: Authorization, query: token, cookie: jwt", + TokenHeadName: "Bearer", + TimeFunc: time.Now, + }) +} + +func cristalhq() (interface{}, error) { + key := []byte(`key3`) + return cristal.NewSignerHS(cristal.HS256, key) // BAD +} + +func josev3() (interface{}, error) { + key := []byte("key4") + return jose_v3.NewSigner(jose_v3.SigningKey{Algorithm: "", Key: key}, nil) // BAD +} +func josev3_2() (interface{}, error) { + key2 := []byte("key5") + return jose_v3.NewEncrypter( + "", + jose_v3.Recipient{ + Algorithm: "", + Key: key2, // BAD + }, + nil) +} + +func josev2() (interface{}, error) { + key := []byte("key6") + + return jose_v2.NewEncrypter( + "", + jose_v2.Recipient{Algorithm: "", Key: key}, // BAD + nil, + ) +} +func jose_v2_2() (interface{}, error) { + key2 := []byte("key7") + + return jose_v2.NewSigner(jose_v2.SigningKey{Algorithm: "", Key: key2}, nil) // BAD +} + +func go_kit() interface{} { + var ( + kid = "kid" + key = []byte("key8") + + mapClaims = gjwt.MapClaims{"user": "go-kit"} + ) + // e := func(ctx context.Context, i interface{}) (interface{}, error) { return ctx, nil } + + return gokit.NewSigner(kid, key, nil, mapClaims) // BAD +} + +func lejwt() (interface{}, error) { + sharedKey := []byte("key9") + return le.New(sharedKey) // BAD +} + +var sharedKeyglobal = []byte("key10") + +func lejwt2() (interface{}, error) { + return le.New(sharedKeyglobal) // BAD +} + +func BarrierGuardTest() (interface{}, error) { + sharedKey := "" + if sharedKey != "" { + return le.New([]byte(sharedKey)) // GOOD + } + return "", nil +} + +func main() { + return +} diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/appleboy/gin-jwt/v2/stub.go b/go/ql/test/experimental/CWE-321/vendor/github.com/appleboy/gin-jwt/v2/stub.go new file mode 100644 index 000000000000..87a117f1f921 --- /dev/null +++ b/go/ql/test/experimental/CWE-321/vendor/github.com/appleboy/gin-jwt/v2/stub.go @@ -0,0 +1,93 @@ +// Code generated by depstubber. DO NOT EDIT. +// This is a simple stub for github.com/appleboy/gin-jwt/v2, strictly for use in testing. + +// See the LICENSE file for information about the licensing of the original library. +// Source: github.com/appleboy/gin-jwt/v2 (exports: GinJWTMiddleware; functions: New) + +// Package gin is a stub of github.com/appleboy/gin-jwt/v2, generated by depstubber. +package gin + +import ( + http "net/http" + time "time" +) + +type GinJWTMiddleware struct { + Realm string + SigningAlgorithm string + Key []byte + KeyFunc func(interface{}) (interface{}, error) + Timeout time.Duration + MaxRefresh time.Duration + Authenticator func(interface{}) (interface{}, error) + Authorizator func(interface{}, interface{}) bool + PayloadFunc func(interface{}) MapClaims + Unauthorized func(interface{}, int, string) + LoginResponse func(interface{}, int, string, time.Time) + LogoutResponse func(interface{}, int) + RefreshResponse func(interface{}, int, string, time.Time) + IdentityHandler func(interface{}) interface{} + IdentityKey string + TokenLookup string + TokenHeadName string + TimeFunc func() time.Time + HTTPStatusMessageFunc func(error, interface{}) string + PrivKeyFile string + PrivKeyBytes []byte + PubKeyFile string + PrivateKeyPassphrase string + PubKeyBytes []byte + SendCookie bool + CookieMaxAge time.Duration + SecureCookie bool + CookieHTTPOnly bool + CookieDomain string + SendAuthorization bool + DisabledAbort bool + CookieName string + CookieSameSite http.SameSite +} + +func (_ *GinJWTMiddleware) CheckIfTokenExpire(_ interface{}) (interface{}, error) { + return nil, nil +} + +func (_ *GinJWTMiddleware) GetClaimsFromJWT(_ interface{}) (MapClaims, error) { + return nil, nil +} + +func (_ *GinJWTMiddleware) LoginHandler(_ interface{}) {} + +func (_ *GinJWTMiddleware) LogoutHandler(_ interface{}) {} + +func (_ *GinJWTMiddleware) MiddlewareFunc() interface{} { + return nil +} + +func (_ *GinJWTMiddleware) MiddlewareInit() error { + return nil +} + +func (_ *GinJWTMiddleware) ParseToken(_ interface{}) (interface{}, error) { + return nil, nil +} + +func (_ *GinJWTMiddleware) ParseTokenString(_ string) (interface{}, error) { + return nil, nil +} + +func (_ *GinJWTMiddleware) RefreshHandler(_ interface{}) {} + +func (_ *GinJWTMiddleware) RefreshToken(_ interface{}) (string, time.Time, error) { + return "", time.Time{}, nil +} + +func (_ *GinJWTMiddleware) TokenGenerator(_ interface{}) (string, time.Time, error) { + return "", time.Time{}, nil +} + +type MapClaims map[string]interface{} + +func New(_ *GinJWTMiddleware) (*GinJWTMiddleware, error) { + return nil, nil +} diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/stub.go b/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/stub.go new file mode 100644 index 000000000000..c4f718e4f1a8 --- /dev/null +++ b/go/ql/test/experimental/CWE-321/vendor/github.com/cristalhq/jwt/v3/stub.go @@ -0,0 +1,26 @@ +// Code generated by depstubber. DO NOT EDIT. +// This is a simple stub for github.com/cristalhq/jwt/v3, strictly for use in testing. + +// See the LICENSE file for information about the licensing of the original library. +// Source: github.com/cristalhq/jwt/v3 (exports: Signer; functions: NewSignerHS,HS256) + +// Package jwt is a stub of github.com/cristalhq/jwt/v3, generated by depstubber. +package jwt + +type Algorithm string + +func (_ Algorithm) String() string { + return "" +} + +var HS256 Algorithm = "" + +func NewSignerHS(_ Algorithm, _ []byte) (Signer, error) { + return nil, nil +} + +type Signer interface { + Algorithm() Algorithm + Sign(_ []byte) ([]byte, error) + SignSize() int +} diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/stub.go b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/stub.go new file mode 100644 index 000000000000..f941716f925f --- /dev/null +++ b/go/ql/test/experimental/CWE-321/vendor/github.com/gin-gonic/gin/stub.go @@ -0,0 +1,681 @@ +// 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: New) + +// Package gin is a stub of github.com/gin-gonic/gin, generated by depstubber. +package gin + +import ( + bufio "bufio" + template "html/template" + io "io" + multipart "mime/multipart" + net "net" + http "net/http" + time "time" +) + +type Context struct { + Request *http.Request + Writer ResponseWriter + Params Params + Keys map[string]interface{} + Errors interface{} + Accepted []string +} + +func (_ *Context) Abort() {} + +func (_ *Context) AbortWithError(_ int, _ error) *Error { + return nil +} + +func (_ *Context) AbortWithStatus(_ int) {} + +func (_ *Context) AbortWithStatusJSON(_ int, _ interface{}) {} + +func (_ *Context) AsciiJSON(_ int, _ interface{}) {} + +func (_ *Context) Bind(_ interface{}) error { + return nil +} + +func (_ *Context) BindHeader(_ interface{}) error { + return nil +} + +func (_ *Context) BindJSON(_ interface{}) error { + return nil +} + +func (_ *Context) BindQuery(_ interface{}) error { + return nil +} + +func (_ *Context) BindUri(_ interface{}) error { + return nil +} + +func (_ *Context) BindWith(_ interface{}, _ interface{}) error { + return nil +} + +func (_ *Context) BindXML(_ interface{}) error { + return nil +} + +func (_ *Context) BindYAML(_ interface{}) error { + return nil +} + +func (_ *Context) ClientIP() string { + return "" +} + +func (_ *Context) ContentType() string { + return "" +} + +func (_ *Context) Cookie(_ string) (string, error) { + return "", nil +} + +func (_ *Context) Copy() *Context { + return nil +} + +func (_ *Context) Data(_ int, _ string, _ []byte) {} + +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() error { + return nil +} + +func (_ *Context) Error(_ error) *Error { + return nil +} + +func (_ *Context) File(_ string) {} + +func (_ *Context) FileAttachment(_ string, _ string) {} + +func (_ *Context) FileFromFS(_ string, _ http.FileSystem) {} + +func (_ *Context) FormFile(_ string) (*multipart.FileHeader, error) { + 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() ([]byte, error) { + 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) GetUint(_ string) uint { + return 0 +} + +func (_ *Context) GetUint64(_ string) uint64 { + return 0 +} + +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, error) { + return nil, nil +} + +func (_ *Context) MustBindWith(_ interface{}, _ interface{}) error { + 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) RemoteIP() (net.IP, bool) { + return nil, false +} + +func (_ *Context) Render(_ int, _ interface{}) {} + +func (_ *Context) SSEvent(_ string, _ interface{}) {} + +func (_ *Context) SaveUploadedFile(_ *multipart.FileHeader, _ string) error { + 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{}) error { + return nil +} + +func (_ *Context) ShouldBindBodyWith(_ interface{}, _ interface{}) error { + return nil +} + +func (_ *Context) ShouldBindHeader(_ interface{}) error { + return nil +} + +func (_ *Context) ShouldBindJSON(_ interface{}) error { + return nil +} + +func (_ *Context) ShouldBindQuery(_ interface{}) error { + return nil +} + +func (_ *Context) ShouldBindUri(_ interface{}) error { + return nil +} + +func (_ *Context) ShouldBindWith(_ interface{}, _ interface{}) error { + return nil +} + +func (_ *Context) ShouldBindXML(_ interface{}) error { + return nil +} + +func (_ *Context) ShouldBindYAML(_ interface{}) error { + 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 Engine struct { + RouterGroup RouterGroup + RedirectTrailingSlash bool + RedirectFixedPath bool + HandleMethodNotAllowed bool + ForwardedByClientIP bool + AppEngine bool + UseRawPath bool + UnescapePathValues bool + RemoveExtraSlash bool + RemoteIPHeaders []string + TrustedPlatform string + MaxMultipartMemory int64 + HTMLRender interface{} + FuncMap template.FuncMap +} + +func (_ *Engine) Any(_ string, _ ...HandlerFunc) IRoutes { + return nil +} + +func (_ *Engine) BasePath() string { + return "" +} + +func (_ *Engine) DELETE(_ string, _ ...HandlerFunc) IRoutes { + return nil +} + +func (_ *Engine) Delims(_ string, _ string) *Engine { + return nil +} + +func (_ *Engine) GET(_ string, _ ...HandlerFunc) IRoutes { + return nil +} + +func (_ *Engine) Group(_ string, _ ...HandlerFunc) *RouterGroup { + return nil +} + +func (_ *Engine) HEAD(_ string, _ ...HandlerFunc) IRoutes { + return nil +} + +func (_ *Engine) Handle(_ string, _ string, _ ...HandlerFunc) IRoutes { + return nil +} + +func (_ *Engine) HandleContext(_ *Context) {} + +func (_ *Engine) LoadHTMLFiles(_ ...string) {} + +func (_ *Engine) LoadHTMLGlob(_ string) {} + +func (_ *Engine) NoMethod(_ ...HandlerFunc) {} + +func (_ *Engine) NoRoute(_ ...HandlerFunc) {} + +func (_ *Engine) OPTIONS(_ string, _ ...HandlerFunc) IRoutes { + return nil +} + +func (_ *Engine) PATCH(_ string, _ ...HandlerFunc) IRoutes { + return nil +} + +func (_ *Engine) POST(_ string, _ ...HandlerFunc) IRoutes { + return nil +} + +func (_ *Engine) PUT(_ string, _ ...HandlerFunc) IRoutes { + return nil +} + +func (_ *Engine) Routes() RoutesInfo { + return nil +} + +func (_ *Engine) Run(_ ...string) error { + return nil +} + +func (_ *Engine) RunFd(_ int) error { + return nil +} + +func (_ *Engine) RunListener(_ net.Listener) error { + return nil +} + +func (_ *Engine) RunTLS(_ string, _ string, _ string) error { + return nil +} + +func (_ *Engine) RunUnix(_ string) error { + return nil +} + +func (_ *Engine) SecureJsonPrefix(_ string) *Engine { + return nil +} + +func (_ *Engine) ServeHTTP(_ http.ResponseWriter, _ *http.Request) {} + +func (_ *Engine) SetFuncMap(_ template.FuncMap) {} + +func (_ *Engine) SetHTMLTemplate(_ *template.Template) {} + +func (_ *Engine) SetTrustedProxies(_ []string) error { + return nil +} + +func (_ *Engine) Static(_ string, _ string) IRoutes { + return nil +} + +func (_ *Engine) StaticFS(_ string, _ http.FileSystem) IRoutes { + return nil +} + +func (_ *Engine) StaticFile(_ string, _ string) IRoutes { + return nil +} + +func (_ *Engine) Use(_ ...HandlerFunc) IRoutes { + return nil +} + +type Error struct { + Err error + 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() ([]byte, error) { + return nil, nil +} + +func (_ *Error) SetMeta(_ interface{}) *Error { + return nil +} + +func (_ *Error) SetType(_ ErrorType) *Error { + return nil +} + +func (_ *Error) Unwrap() error { + return nil +} + +type ErrorType uint64 + +type HandlerFunc func(*Context) + +type HandlersChain []HandlerFunc + +func (_ HandlersChain) Last() HandlerFunc { + return nil +} + +type IRoutes interface { + Any(_ string, _ ...HandlerFunc) IRoutes + DELETE(_ string, _ ...HandlerFunc) IRoutes + GET(_ string, _ ...HandlerFunc) IRoutes + HEAD(_ string, _ ...HandlerFunc) IRoutes + Handle(_ string, _ string, _ ...HandlerFunc) IRoutes + OPTIONS(_ string, _ ...HandlerFunc) IRoutes + PATCH(_ string, _ ...HandlerFunc) IRoutes + POST(_ string, _ ...HandlerFunc) IRoutes + PUT(_ string, _ ...HandlerFunc) IRoutes + Static(_ string, _ string) IRoutes + StaticFS(_ string, _ http.FileSystem) IRoutes + StaticFile(_ string, _ string) IRoutes + Use(_ ...HandlerFunc) IRoutes +} + +type Negotiate struct { + Offered []string + HTMLName string + HTMLData interface{} + JSONData interface{} + XMLData interface{} + YAMLData interface{} + Data interface{} +} + +func New() *Engine { + return nil +} + +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, error) + Pusher() http.Pusher + Size() int + Status() int + Write(_ []byte) (int, error) + WriteHeader(_ int) + WriteHeaderNow() + WriteString(_ string) (int, error) + Written() bool +} + +type RouteInfo struct { + Method string + Path string + Handler string + HandlerFunc HandlerFunc +} + +type RouterGroup struct { + Handlers HandlersChain +} + +func (_ *RouterGroup) Any(_ string, _ ...HandlerFunc) IRoutes { + return nil +} + +func (_ *RouterGroup) BasePath() string { + return "" +} + +func (_ *RouterGroup) DELETE(_ string, _ ...HandlerFunc) IRoutes { + return nil +} + +func (_ *RouterGroup) GET(_ string, _ ...HandlerFunc) IRoutes { + return nil +} + +func (_ *RouterGroup) Group(_ string, _ ...HandlerFunc) *RouterGroup { + return nil +} + +func (_ *RouterGroup) HEAD(_ string, _ ...HandlerFunc) IRoutes { + return nil +} + +func (_ *RouterGroup) Handle(_ string, _ string, _ ...HandlerFunc) IRoutes { + return nil +} + +func (_ *RouterGroup) OPTIONS(_ string, _ ...HandlerFunc) IRoutes { + return nil +} + +func (_ *RouterGroup) PATCH(_ string, _ ...HandlerFunc) IRoutes { + return nil +} + +func (_ *RouterGroup) POST(_ string, _ ...HandlerFunc) IRoutes { + return nil +} + +func (_ *RouterGroup) PUT(_ string, _ ...HandlerFunc) IRoutes { + return nil +} + +func (_ *RouterGroup) Static(_ string, _ string) IRoutes { + return nil +} + +func (_ *RouterGroup) StaticFS(_ string, _ http.FileSystem) IRoutes { + return nil +} + +func (_ *RouterGroup) StaticFile(_ string, _ string) IRoutes { + return nil +} + +func (_ *RouterGroup) Use(_ ...HandlerFunc) IRoutes { + return nil +} + +type RoutesInfo []RouteInfo diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/auth/jwt/stub.go b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/auth/jwt/stub.go new file mode 100644 index 000000000000..b85d079daa57 --- /dev/null +++ b/go/ql/test/experimental/CWE-321/vendor/github.com/go-kit/kit/auth/jwt/stub.go @@ -0,0 +1,12 @@ +// Code generated by depstubber. DO NOT EDIT. +// This is a simple stub for github.com/go-kit/kit/auth/jwt, strictly for use in testing. + +// See the LICENSE file for information about the licensing of the original library. +// Source: github.com/go-kit/kit/auth/jwt (exports: ; functions: NewSigner) + +// Package jwt is a stub of github.com/go-kit/kit/auth/jwt, generated by depstubber. +package jwt + +func NewSigner(_ string, _ []byte, _ interface{}, _ interface{}) interface{} { + return nil +} diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/stub.go b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/stub.go new file mode 100644 index 000000000000..d83739d7fde9 --- /dev/null +++ b/go/ql/test/experimental/CWE-321/vendor/github.com/golang-jwt/jwt/v4/stub.go @@ -0,0 +1,328 @@ +// Code generated by depstubber. DO NOT EDIT. +// This is a simple stub for github.com/golang-jwt/jwt/v4, strictly for use in testing. + +// See the LICENSE file for information about the licensing of the original library. +// Source: github.com/golang-jwt/jwt/v4 (exports: MapClaims,RegisteredClaims,SigningMethodRSA,SigningMethodHMAC,Token; functions: NewNumericDate,NewWithClaims) + +// Package jwt is a stub of github.com/golang-jwt/jwt/v4, generated by depstubber. +package jwt + +import ( + crypto "crypto" + time "time" +) + +type ClaimStrings []string + +func (_ ClaimStrings) MarshalJSON() ([]byte, error) { + return nil, nil +} + +func (_ *ClaimStrings) UnmarshalJSON(_ []byte) error { + return nil +} + +type Claims interface { + Valid() error +} + +type MapClaims map[string]interface{} + +func (_ MapClaims) Valid() error { + return nil +} + +func (_ MapClaims) VerifyAudience(_ string, _ bool) bool { + return false +} + +func (_ MapClaims) VerifyExpiresAt(_ int64, _ bool) bool { + return false +} + +func (_ MapClaims) VerifyIssuedAt(_ int64, _ bool) bool { + return false +} + +func (_ MapClaims) VerifyIssuer(_ string, _ bool) bool { + return false +} + +func (_ MapClaims) VerifyNotBefore(_ int64, _ bool) bool { + return false +} + +func NewNumericDate(_ time.Time) *NumericDate { + return nil +} + +func NewWithClaims(_ SigningMethod, _ Claims) *Token { + return nil +} + +type NumericDate struct { + Time time.Time +} + +func (_ NumericDate) Add(_ time.Duration) time.Time { + return time.Time{} +} + +func (_ NumericDate) AddDate(_ int, _ int, _ int) time.Time { + return time.Time{} +} + +func (_ NumericDate) After(_ time.Time) bool { + return false +} + +func (_ NumericDate) AppendFormat(_ []byte, _ string) []byte { + return nil +} + +func (_ NumericDate) Before(_ time.Time) bool { + return false +} + +func (_ NumericDate) Clock() (int, int, int) { + return 0, 0, 0 +} + +func (_ NumericDate) Date() (int, time.Month, int) { + return 0, 0, 0 +} + +func (_ NumericDate) Day() int { + return 0 +} + +func (_ NumericDate) Equal(_ time.Time) bool { + return false +} + +func (_ NumericDate) Format(_ string) string { + return "" +} + +func (_ NumericDate) GoString() string { + return "" +} + +func (_ NumericDate) GobEncode() ([]byte, error) { + return nil, nil +} + +func (_ NumericDate) Hour() int { + return 0 +} + +func (_ NumericDate) ISOWeek() (int, int) { + return 0, 0 +} + +func (_ NumericDate) In(_ *time.Location) time.Time { + return time.Time{} +} + +func (_ NumericDate) IsDST() bool { + return false +} + +func (_ NumericDate) IsZero() bool { + return false +} + +func (_ NumericDate) Local() time.Time { + return time.Time{} +} + +func (_ NumericDate) Location() *time.Location { + return nil +} + +func (_ NumericDate) MarshalBinary() ([]byte, error) { + return nil, nil +} + +func (_ NumericDate) MarshalJSON() ([]byte, error) { + return nil, nil +} + +func (_ NumericDate) MarshalText() ([]byte, error) { + return nil, nil +} + +func (_ NumericDate) Minute() int { + return 0 +} + +func (_ NumericDate) Month() time.Month { + return 0 +} + +func (_ NumericDate) Nanosecond() int { + return 0 +} + +func (_ NumericDate) Round(_ time.Duration) time.Time { + return time.Time{} +} + +func (_ NumericDate) Second() int { + return 0 +} + +func (_ NumericDate) String() string { + return "" +} + +func (_ NumericDate) Sub(_ time.Time) time.Duration { + return 0 +} + +func (_ NumericDate) Truncate(_ time.Duration) time.Time { + return time.Time{} +} + +func (_ NumericDate) UTC() time.Time { + return time.Time{} +} + +func (_ NumericDate) Unix() int64 { + return 0 +} + +func (_ NumericDate) UnixMicro() int64 { + return 0 +} + +func (_ NumericDate) UnixMilli() int64 { + return 0 +} + +func (_ NumericDate) UnixNano() int64 { + return 0 +} + +func (_ NumericDate) Weekday() time.Weekday { + return 0 +} + +func (_ NumericDate) Year() int { + return 0 +} + +func (_ NumericDate) YearDay() int { + return 0 +} + +func (_ NumericDate) Zone() (string, int) { + return "", 0 +} + +func (_ *NumericDate) GobDecode(_ []byte) error { + return nil +} + +func (_ *NumericDate) UnmarshalBinary(_ []byte) error { + return nil +} + +func (_ *NumericDate) UnmarshalJSON(_ []byte) error { + return nil +} + +func (_ *NumericDate) UnmarshalText(_ []byte) error { + return nil +} + +type RegisteredClaims struct { + Issuer string + Subject string + Audience ClaimStrings + ExpiresAt *NumericDate + NotBefore *NumericDate + IssuedAt *NumericDate + ID string +} + +func (_ RegisteredClaims) Valid() error { + return nil +} + +func (_ *RegisteredClaims) VerifyAudience(_ string, _ bool) bool { + return false +} + +func (_ *RegisteredClaims) VerifyExpiresAt(_ time.Time, _ bool) bool { + return false +} + +func (_ *RegisteredClaims) VerifyIssuedAt(_ time.Time, _ bool) bool { + return false +} + +func (_ *RegisteredClaims) VerifyIssuer(_ string, _ bool) bool { + return false +} + +func (_ *RegisteredClaims) VerifyNotBefore(_ time.Time, _ bool) bool { + return false +} + +type SigningMethod interface { + Alg() string + Sign(_ string, _ interface{}) (string, error) + Verify(_ string, _ string, _ interface{}) error +} + +type SigningMethodHMAC struct { + Name string + Hash crypto.Hash +} + +func (_ *SigningMethodHMAC) Alg() string { + return "" +} + +func (_ *SigningMethodHMAC) Sign(_ string, _ interface{}) (string, error) { + return "", nil +} + +func (_ *SigningMethodHMAC) Verify(_ string, _ string, _ interface{}) error { + return nil +} + +type SigningMethodRSA struct { + Name string + Hash crypto.Hash +} + +func (_ *SigningMethodRSA) Alg() string { + return "" +} + +func (_ *SigningMethodRSA) Sign(_ string, _ interface{}) (string, error) { + return "", nil +} + +func (_ *SigningMethodRSA) Verify(_ string, _ string, _ interface{}) error { + return nil +} + +type Token struct { + Raw string + Method SigningMethod + Header map[string]interface{} + Claims Claims + Signature string + Valid bool +} + +func (_ *Token) SignedString(_ interface{}) (string, error) { + return "", nil +} + +func (_ *Token) SigningString() (string, error) { + return "", nil +} diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/lestrrat/go-jwx/jwk/stub.go b/go/ql/test/experimental/CWE-321/vendor/github.com/lestrrat/go-jwx/jwk/stub.go new file mode 100644 index 000000000000..de88951dd465 --- /dev/null +++ b/go/ql/test/experimental/CWE-321/vendor/github.com/lestrrat/go-jwx/jwk/stub.go @@ -0,0 +1,39 @@ +// Code generated by depstubber. DO NOT EDIT. +// This is a simple stub for github.com/lestrrat/go-jwx/jwk, strictly for use in testing. + +// See the LICENSE file for information about the licensing of the original library. +// Source: github.com/lestrrat/go-jwx/jwk (exports: ; functions: New) + +// Package jwk is a stub of github.com/lestrrat/go-jwx/jwk, generated by depstubber. +package jwk + +import ( + crypto "crypto" + x509 "crypto/x509" +) + +type Key interface { + Algorithm() string + ExtractMap(_ map[string]interface{}) error + Get(_ string) (interface{}, bool) + KeyID() string + KeyOps() []KeyOperation + KeyType() interface{} + KeyUsage() string + Materialize() (interface{}, error) + PopulateMap(_ map[string]interface{}) error + Remove(_ string) + Set(_ string, _ interface{}) error + Thumbprint(_ crypto.Hash) ([]byte, error) + Walk(_ func(string, interface{}) error) error + X509CertChain() []*x509.Certificate + X509CertThumbprint() string + X509CertThumbprintS256() string + X509URL() string +} + +type KeyOperation string + +func New(_ interface{}) (Key, error) { + return nil, nil +} diff --git a/go/ql/test/experimental/CWE-321/vendor/github.com/square/go-jose/v3/stub.go b/go/ql/test/experimental/CWE-321/vendor/github.com/square/go-jose/v3/stub.go new file mode 100644 index 000000000000..cf34d6ec99d4 --- /dev/null +++ b/go/ql/test/experimental/CWE-321/vendor/github.com/square/go-jose/v3/stub.go @@ -0,0 +1,219 @@ +// Code generated by depstubber. DO NOT EDIT. +// This is a simple stub for github.com/square/go-jose/v3, strictly for use in testing. + +// See the LICENSE file for information about the licensing of the original library. +// Source: github.com/square/go-jose/v3 (exports: Recipient; functions: NewEncrypter,NewSigner) + +// Package go_pkg is a stub of github.com/square/go-jose/v3, generated by depstubber. +package go_pkg + +import ( + crypto "crypto" + x509 "crypto/x509" + url "net/url" +) + +type CompressionAlgorithm string + +type ContentEncryption string + +type ContentType string + +type Encrypter interface { + Encrypt(_ []byte) (*JSONWebEncryption, error) + EncryptWithAuthData(_ []byte, _ []byte) (*JSONWebEncryption, error) + Options() EncrypterOptions +} + +type EncrypterOptions struct { + Compression CompressionAlgorithm + ExtraHeaders map[HeaderKey]interface{} +} + +func (_ *EncrypterOptions) WithContentType(_ ContentType) *EncrypterOptions { + return nil +} + +func (_ *EncrypterOptions) WithHeader(_ HeaderKey, _ interface{}) *EncrypterOptions { + return nil +} + +func (_ *EncrypterOptions) WithType(_ ContentType) *EncrypterOptions { + return nil +} + +type Header struct { + KeyID string + JSONWebKey *JSONWebKey + Algorithm string + Nonce string + ExtraHeaders map[HeaderKey]interface{} +} + +func (_ Header) Certificates(_ x509.VerifyOptions) ([][]*x509.Certificate, error) { + return nil, nil +} + +type HeaderKey string + +type JSONWebEncryption struct { + Header Header +} + +func (_ JSONWebEncryption) CompactSerialize() (string, error) { + return "", nil +} + +func (_ JSONWebEncryption) Decrypt(_ interface{}) ([]byte, error) { + return nil, nil +} + +func (_ JSONWebEncryption) DecryptMulti(_ interface{}) (int, Header, []byte, error) { + return 0, Header{}, nil, nil +} + +func (_ JSONWebEncryption) FullSerialize() string { + return "" +} + +func (_ JSONWebEncryption) GetAuthData() []byte { + return nil +} + +type JSONWebKey struct { + Key interface{} + KeyID string + Algorithm string + Use string + Certificates []*x509.Certificate + CertificatesURL *url.URL + CertificateThumbprintSHA1 []byte + CertificateThumbprintSHA256 []byte +} + +func (_ JSONWebKey) MarshalJSON() ([]byte, error) { + return nil, nil +} + +func (_ *JSONWebKey) IsPublic() bool { + return false +} + +func (_ *JSONWebKey) Public() JSONWebKey { + return JSONWebKey{} +} + +func (_ *JSONWebKey) Thumbprint(_ crypto.Hash) ([]byte, error) { + return nil, nil +} + +func (_ *JSONWebKey) UnmarshalJSON(_ []byte) error { + return nil +} + +func (_ *JSONWebKey) Valid() bool { + return false +} + +type JSONWebSignature struct { + Signatures []Signature +} + +func (_ JSONWebSignature) CompactSerialize() (string, error) { + return "", nil +} + +func (_ JSONWebSignature) DetachedCompactSerialize() (string, error) { + return "", nil +} + +func (_ JSONWebSignature) DetachedVerify(_ []byte, _ interface{}) error { + return nil +} + +func (_ JSONWebSignature) DetachedVerifyMulti(_ []byte, _ interface{}) (int, Signature, error) { + return 0, Signature{}, nil +} + +func (_ JSONWebSignature) FullSerialize() string { + return "" +} + +func (_ JSONWebSignature) UnsafePayloadWithoutVerification() []byte { + return nil +} + +func (_ JSONWebSignature) Verify(_ interface{}) ([]byte, error) { + return nil, nil +} + +func (_ JSONWebSignature) VerifyMulti(_ interface{}) (int, Signature, []byte, error) { + return 0, Signature{}, nil, nil +} + +type KeyAlgorithm string + +func NewEncrypter(_ ContentEncryption, _ Recipient, _ *EncrypterOptions) (Encrypter, error) { + return nil, nil +} + +func NewSigner(_ SigningKey, _ *SignerOptions) (Signer, error) { + return nil, nil +} + +type NonceSource interface { + Nonce() (string, error) +} + +type Recipient struct { + Algorithm KeyAlgorithm + Key interface{} + KeyID string + PBES2Count int + PBES2Salt []byte +} + +type Signature struct { + Header Header + Protected Header + Unprotected Header + Signature []byte +} + +type SignatureAlgorithm string + +type Signer interface { + Options() SignerOptions + Sign(_ []byte) (*JSONWebSignature, error) +} + +type SignerOptions struct { + NonceSource NonceSource + EmbedJWK bool + ExtraHeaders map[HeaderKey]interface{} +} + +func (_ *SignerOptions) WithBase64(_ bool) *SignerOptions { + return nil +} + +func (_ *SignerOptions) WithContentType(_ ContentType) *SignerOptions { + return nil +} + +func (_ *SignerOptions) WithCritical(_ ...string) *SignerOptions { + return nil +} + +func (_ *SignerOptions) WithHeader(_ HeaderKey, _ interface{}) *SignerOptions { + return nil +} + +func (_ *SignerOptions) WithType(_ ContentType) *SignerOptions { + return nil +} + +type SigningKey struct { + Algorithm SignatureAlgorithm + Key interface{} +} diff --git a/go/ql/test/experimental/CWE-321/vendor/gopkg.in/square/go-jose.v2/stub.go b/go/ql/test/experimental/CWE-321/vendor/gopkg.in/square/go-jose.v2/stub.go new file mode 100644 index 000000000000..cbbbd9a4df8b --- /dev/null +++ b/go/ql/test/experimental/CWE-321/vendor/gopkg.in/square/go-jose.v2/stub.go @@ -0,0 +1,219 @@ +// Code generated by depstubber. DO NOT EDIT. +// This is a simple stub for gopkg.in/square/go-jose.v2, strictly for use in testing. + +// See the LICENSE file for information about the licensing of the original library. +// Source: gopkg.in/square/go-jose.v2 (exports: Recipient; functions: NewEncrypter,NewSigner) + +// Package go_pkg is a stub of gopkg.in/square/go-jose.v2, generated by depstubber. +package go_pkg + +import ( + crypto "crypto" + x509 "crypto/x509" + url "net/url" +) + +type CompressionAlgorithm string + +type ContentEncryption string + +type ContentType string + +type Encrypter interface { + Encrypt(_ []byte) (*JSONWebEncryption, error) + EncryptWithAuthData(_ []byte, _ []byte) (*JSONWebEncryption, error) + Options() EncrypterOptions +} + +type EncrypterOptions struct { + Compression CompressionAlgorithm + ExtraHeaders map[HeaderKey]interface{} +} + +func (_ *EncrypterOptions) WithContentType(_ ContentType) *EncrypterOptions { + return nil +} + +func (_ *EncrypterOptions) WithHeader(_ HeaderKey, _ interface{}) *EncrypterOptions { + return nil +} + +func (_ *EncrypterOptions) WithType(_ ContentType) *EncrypterOptions { + return nil +} + +type Header struct { + KeyID string + JSONWebKey *JSONWebKey + Algorithm string + Nonce string + ExtraHeaders map[HeaderKey]interface{} +} + +func (_ Header) Certificates(_ x509.VerifyOptions) ([][]*x509.Certificate, error) { + return nil, nil +} + +type HeaderKey string + +type JSONWebEncryption struct { + Header Header +} + +func (_ JSONWebEncryption) CompactSerialize() (string, error) { + return "", nil +} + +func (_ JSONWebEncryption) Decrypt(_ interface{}) ([]byte, error) { + return nil, nil +} + +func (_ JSONWebEncryption) DecryptMulti(_ interface{}) (int, Header, []byte, error) { + return 0, Header{}, nil, nil +} + +func (_ JSONWebEncryption) FullSerialize() string { + return "" +} + +func (_ JSONWebEncryption) GetAuthData() []byte { + return nil +} + +type JSONWebKey struct { + Key interface{} + KeyID string + Algorithm string + Use string + Certificates []*x509.Certificate + CertificatesURL *url.URL + CertificateThumbprintSHA1 []byte + CertificateThumbprintSHA256 []byte +} + +func (_ JSONWebKey) MarshalJSON() ([]byte, error) { + return nil, nil +} + +func (_ *JSONWebKey) IsPublic() bool { + return false +} + +func (_ *JSONWebKey) Public() JSONWebKey { + return JSONWebKey{} +} + +func (_ *JSONWebKey) Thumbprint(_ crypto.Hash) ([]byte, error) { + return nil, nil +} + +func (_ *JSONWebKey) UnmarshalJSON(_ []byte) error { + return nil +} + +func (_ *JSONWebKey) Valid() bool { + return false +} + +type JSONWebSignature struct { + Signatures []Signature +} + +func (_ JSONWebSignature) CompactSerialize() (string, error) { + return "", nil +} + +func (_ JSONWebSignature) DetachedCompactSerialize() (string, error) { + return "", nil +} + +func (_ JSONWebSignature) DetachedVerify(_ []byte, _ interface{}) error { + return nil +} + +func (_ JSONWebSignature) DetachedVerifyMulti(_ []byte, _ interface{}) (int, Signature, error) { + return 0, Signature{}, nil +} + +func (_ JSONWebSignature) FullSerialize() string { + return "" +} + +func (_ JSONWebSignature) UnsafePayloadWithoutVerification() []byte { + return nil +} + +func (_ JSONWebSignature) Verify(_ interface{}) ([]byte, error) { + return nil, nil +} + +func (_ JSONWebSignature) VerifyMulti(_ interface{}) (int, Signature, []byte, error) { + return 0, Signature{}, nil, nil +} + +type KeyAlgorithm string + +func NewEncrypter(_ ContentEncryption, _ Recipient, _ *EncrypterOptions) (Encrypter, error) { + return nil, nil +} + +func NewSigner(_ SigningKey, _ *SignerOptions) (Signer, error) { + return nil, nil +} + +type NonceSource interface { + Nonce() (string, error) +} + +type Recipient struct { + Algorithm KeyAlgorithm + Key interface{} + KeyID string + PBES2Count int + PBES2Salt []byte +} + +type Signature struct { + Header Header + Protected Header + Unprotected Header + Signature []byte +} + +type SignatureAlgorithm string + +type Signer interface { + Options() SignerOptions + Sign(_ []byte) (*JSONWebSignature, error) +} + +type SignerOptions struct { + NonceSource NonceSource + EmbedJWK bool + ExtraHeaders map[HeaderKey]interface{} +} + +func (_ *SignerOptions) WithBase64(_ bool) *SignerOptions { + return nil +} + +func (_ *SignerOptions) WithContentType(_ ContentType) *SignerOptions { + return nil +} + +func (_ *SignerOptions) WithCritical(_ ...string) *SignerOptions { + return nil +} + +func (_ *SignerOptions) WithHeader(_ HeaderKey, _ interface{}) *SignerOptions { + return nil +} + +func (_ *SignerOptions) WithType(_ ContentType) *SignerOptions { + return nil +} + +type SigningKey struct { + Algorithm SignatureAlgorithm + Key interface{} +} diff --git a/go/ql/test/experimental/CWE-321/vendor/modules.txt b/go/ql/test/experimental/CWE-321/vendor/modules.txt new file mode 100644 index 000000000000..1a10cd454fb4 --- /dev/null +++ b/go/ql/test/experimental/CWE-321/vendor/modules.txt @@ -0,0 +1,96 @@ +# github.com/appleboy/gin-jwt/v2 v2.8.0 +## explicit +github.com/appleboy/gin-jwt/v2 +# github.com/cristalhq/jwt/v3 v3.1.0 +## explicit +github.com/cristalhq/jwt/v3 +# github.com/gin-gonic/gin v1.7.7 +## explicit +github.com/gin-gonic/gin +# github.com/go-kit/kit v0.12.0 +## explicit +github.com/go-kit/kit +# github.com/golang-jwt/jwt/v4 v4.4.1 +## explicit +github.com/golang-jwt/jwt/v4 +# github.com/lestrrat/go-jwx v0.9.1 +## explicit +github.com/lestrrat/go-jwx +# github.com/square/go-jose/v3 v3.0.0-20200630053402-0a67ce9b0693 +## explicit +github.com/square/go-jose/v3 +# gopkg.in/square/go-jose.v2 v2.6.0 +## explicit +gopkg.in/square/go-jose.v2 +# github.com/davecgh/go-spew v1.1.1 +## explicit +github.com/davecgh/go-spew +# github.com/gin-contrib/sse v0.1.0 +## explicit +github.com/gin-contrib/sse +# github.com/go-kit/log v0.2.0 +## explicit +github.com/go-kit/log +# github.com/go-logfmt/logfmt v0.5.1 +## explicit +github.com/go-logfmt/logfmt +# github.com/go-playground/locales v0.13.0 +## explicit +github.com/go-playground/locales +# github.com/go-playground/universal-translator v0.17.0 +## explicit +github.com/go-playground/universal-translator +# github.com/go-playground/validator/v10 v10.4.1 +## explicit +github.com/go-playground/validator/v10 +# github.com/golang/protobuf v1.5.2 +## explicit +github.com/golang/protobuf +# github.com/json-iterator/go v1.1.12 +## explicit +github.com/json-iterator/go +# github.com/leodido/go-urn v1.2.0 +## explicit +github.com/leodido/go-urn +# github.com/lestrrat/go-pdebug v0.0.0-20180220043741-569c97477ae8 +## explicit +github.com/lestrrat/go-pdebug +# github.com/mattn/go-isatty v0.0.14 +## explicit +github.com/mattn/go-isatty +# github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd +## explicit +github.com/modern-go/concurrent +# github.com/modern-go/reflect2 v1.0.2 +## explicit +github.com/modern-go/reflect2 +# github.com/pkg/errors v0.9.1 +## explicit +github.com/pkg/errors +# github.com/ugorji/go/codec v1.1.7 +## explicit +github.com/ugorji/go/codec +# golang.org/x/crypto v0.0.0-20210915214749-c084706c2272 +## explicit +golang.org/x/crypto +# golang.org/x/net v0.0.0-20210917221730-978cfadd31cf +## explicit +golang.org/x/net +# golang.org/x/sys v0.0.0-20210917161153-d61c044b1678 +## explicit +golang.org/x/sys +# golang.org/x/text v0.3.7 +## explicit +golang.org/x/text +# google.golang.org/genproto v0.0.0-20210917145530-b395a37504d4 +## explicit +google.golang.org/genproto +# google.golang.org/grpc v1.40.0 +## explicit +google.golang.org/grpc +# google.golang.org/protobuf v1.27.1 +## explicit +google.golang.org/protobuf +# gopkg.in/yaml.v2 v2.2.8 +## explicit +gopkg.in/yaml.v2 From e0f74a51acdc8541bb094924d8d386d6e91376e0 Mon Sep 17 00:00:00 2001 From: Porcupiney Hairs Date: Tue, 31 May 2022 17:17:54 +0530 Subject: [PATCH 02/11] Include suggested changes from review. --- .../experimental/CWE-321/HardcodedKeys.qhelp | 2 +- .../experimental/CWE-321/HardcodedKeysLib.qll | 43 ++++++++++--------- .../CWE-321/HardcodedKeys.expected | 42 +++++++++++------- go/ql/test/experimental/CWE-321/main.go | 3 +- 4 files changed, 52 insertions(+), 38 deletions(-) diff --git a/go/ql/src/experimental/CWE-321/HardcodedKeys.qhelp b/go/ql/src/experimental/CWE-321/HardcodedKeys.qhelp index a02812296a4b..b641cbda1849 100644 --- a/go/ql/src/experimental/CWE-321/HardcodedKeys.qhelp +++ b/go/ql/src/experimental/CWE-321/HardcodedKeys.qhelp @@ -18,7 +18,7 @@

    - Generating a crytograhically secure secret key during application initialization and using this generated key for future JWT signing requests can prevent this vulnerability. + Generating a cryptograhically secure secret key during application initialization and using this generated key for future JWT signing requests can prevent this vulnerability.

    diff --git a/go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll b/go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll index 30bada97aa30..027f42e6187c 100644 --- a/go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll +++ b/go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll @@ -65,26 +65,20 @@ module HardcodedKeys { "github.com/form3tech-oss/jwt-go", "github.com/ory/fosite/token/jwt" ] | - ( - exists(DataFlow::MethodCallNode m | - // Models the `SignedString` method - // `func (t *Token) SignedString(key interface{}) (string, error)` - m.getTarget().hasQualifiedName(pkg, "Token", "SignedString") - | - this = m.getArgument(0) - ) + exists(DataFlow::MethodCallNode m | + // Models the `SignedString` method + // `func (t *Token) SignedString(key interface{}) (string, error)` + m.getTarget().hasQualifiedName(pkg, "Token", "SignedString") and + this = m.getArgument(0) or - exists(DataFlow::MethodCallNode m | - // Model the `Sign` method of the `SigningMethod` interface - // type SigningMethod interface { - // Verify(signingString, signature string, key interface{}) error - // Sign(signingString string, key interface{}) (string, error) - // Alg() string - // } - m.getTarget().hasQualifiedName(pkg, "SigningMethod", "Sign") - | - this = m.getArgument(1) - ) + // Model the `Sign` method of the `SigningMethod` interface + // type SigningMethod interface { + // Verify(signingString, signature string, key interface{}) error + // Sign(signingString string, key interface{}) (string, error) + // Alg() string + // } + m.getTarget().hasQualifiedName(pkg, "SigningMethod", "Sign") and + this = m.getArgument(1) ) ) } @@ -240,12 +234,21 @@ module HardcodedKeys { // } exists(DataFlow::CallNode randread, DataFlow::Node rand, DataFlow::ElementReadNode r | randread.getTarget().hasQualifiedName("crypto/rand", "Read") and - TaintTracking::localTaint(randread.getArgument(0).getAPredecessor*().getASuccessor*(), rand) and + TaintTracking::localTaint(any(DataFlow::PostUpdateNode pun | + pun.getPreUpdateNode() = randread.getArgument(0) + ), rand) and ( + // Flow through a ModExpr if any of the operands are tainted. + // For ex, in the case shown above, + // `bytes[i] = characters[x%byte(len(characters))]` + // given x is cryptographically secure random number, + // we can assume that `bytes` is random and cryptographically secure. exists(ModExpr e | e.getAnOperand() = rand.asExpr() | r.reads(this, e.getGlobalValueNumber().getANode()) ) or + // This is an alternative case where the code uses `x` directly instead + // `bytes[i] = characters[x]` r.reads(this.getAPredecessor*(), rand) ) ) diff --git a/go/ql/test/experimental/CWE-321/HardcodedKeys.expected b/go/ql/test/experimental/CWE-321/HardcodedKeys.expected index b50e78b6ebf0..696386398770 100644 --- a/go/ql/test/experimental/CWE-321/HardcodedKeys.expected +++ b/go/ql/test/experimental/CWE-321/HardcodedKeys.expected @@ -14,12 +14,16 @@ edges | main.go:80:16:80:21 | "key6" : string | main.go:80:9:80:22 | type conversion : string | | main.go:89:10:89:23 | type conversion : string | main.go:91:66:91:69 | key2 | | main.go:89:17:89:22 | "key7" : string | main.go:89:10:89:23 | type conversion : string | -| main.go:97:9:97:22 | type conversion : string | main.go:103:30:103:32 | key | +| main.go:97:9:97:22 | type conversion : string | main.go:102:30:102:32 | key | | main.go:97:16:97:21 | "key8" : string | main.go:97:9:97:22 | type conversion : string | -| main.go:107:15:107:28 | type conversion : string | main.go:108:16:108:24 | sharedKey | -| main.go:107:22:107:27 | "key9" : string | main.go:107:15:107:28 | type conversion : string | -| main.go:111:23:111:37 | type conversion : string | main.go:114:16:114:30 | sharedKeyglobal | -| main.go:111:30:111:36 | "key10" : string | main.go:111:23:111:37 | type conversion : string | +| main.go:106:15:106:28 | type conversion : string | main.go:107:16:107:24 | sharedKey | +| main.go:106:22:106:27 | "key9" : string | main.go:106:15:106:28 | type conversion : string | +| main.go:110:23:110:37 | type conversion : string | main.go:113:16:113:30 | sharedKeyglobal | +| main.go:110:30:110:36 | "key10" : string | main.go:110:23:110:37 | type conversion : string | +| sanitizer.go:17:9:17:21 | type conversion : string | sanitizer.go:18:44:18:46 | key | +| sanitizer.go:17:16:17:20 | `key` : string | sanitizer.go:17:9:17:21 | type conversion : string | +| sanitizer.go:80:10:80:14 | "asd" : string | sanitizer.go:99:2:99:24 | ... := ...[0] : string | +| sanitizer.go:99:2:99:24 | ... := ...[0] : string | sanitizer.go:104:44:104:47 | key4 | nodes | HardcodedKeysBad.go:11:18:11:38 | type conversion : string | semmle.label | type conversion : string | | HardcodedKeysBad.go:11:25:11:37 | "AllYourBase" : string | semmle.label | "AllYourBase" : string | @@ -46,13 +50,19 @@ nodes | main.go:91:66:91:69 | key2 | semmle.label | key2 | | main.go:97:9:97:22 | type conversion : string | semmle.label | type conversion : string | | main.go:97:16:97:21 | "key8" : string | semmle.label | "key8" : string | -| main.go:103:30:103:32 | key | semmle.label | key | -| main.go:107:15:107:28 | type conversion : string | semmle.label | type conversion : string | -| main.go:107:22:107:27 | "key9" : string | semmle.label | "key9" : string | -| main.go:108:16:108:24 | sharedKey | semmle.label | sharedKey | -| main.go:111:23:111:37 | type conversion : string | semmle.label | type conversion : string | -| main.go:111:30:111:36 | "key10" : string | semmle.label | "key10" : string | -| main.go:114:16:114:30 | sharedKeyglobal | semmle.label | sharedKeyglobal | +| main.go:102:30:102:32 | key | semmle.label | key | +| main.go:106:15:106:28 | type conversion : string | semmle.label | type conversion : string | +| main.go:106:22:106:27 | "key9" : string | semmle.label | "key9" : string | +| main.go:107:16:107:24 | sharedKey | semmle.label | sharedKey | +| main.go:110:23:110:37 | type conversion : string | semmle.label | type conversion : string | +| main.go:110:30:110:36 | "key10" : string | semmle.label | "key10" : string | +| main.go:113:16:113:30 | sharedKeyglobal | semmle.label | sharedKeyglobal | +| sanitizer.go:17:9:17:21 | type conversion : string | semmle.label | type conversion : string | +| sanitizer.go:17:16:17:20 | `key` : string | semmle.label | `key` : string | +| sanitizer.go:18:44:18:46 | key | semmle.label | key | +| sanitizer.go:80:10:80:14 | "asd" : string | semmle.label | "asd" : string | +| sanitizer.go:99:2:99:24 | ... := ...[0] : string | semmle.label | ... := ...[0] : string | +| sanitizer.go:104:44:104:47 | key4 | semmle.label | key4 | subpaths #select | HardcodedKeysBad.go:19:28:19:39 | mySigningKey | HardcodedKeysBad.go:11:25:11:37 | "AllYourBase" : string | HardcodedKeysBad.go:19:28:19:39 | mySigningKey | $@ is used to sign a JWT token. | HardcodedKeysBad.go:11:25:11:37 | "AllYourBase" | Hardcoded String | @@ -63,6 +73,8 @@ subpaths | main.go:74:15:74:18 | key2 | main.go:69:17:69:22 | "key5" : string | main.go:74:15:74:18 | key2 | $@ is used to sign a JWT token. | main.go:69:17:69:22 | "key5" | Hardcoded String | | main.go:84:41:84:43 | key | main.go:80:16:80:21 | "key6" : string | main.go:84:41:84:43 | key | $@ is used to sign a JWT token. | main.go:80:16:80:21 | "key6" | Hardcoded String | | main.go:91:66:91:69 | key2 | main.go:89:17:89:22 | "key7" : string | main.go:91:66:91:69 | key2 | $@ is used to sign a JWT token. | main.go:89:17:89:22 | "key7" | Hardcoded String | -| main.go:103:30:103:32 | key | main.go:97:16:97:21 | "key8" : string | main.go:103:30:103:32 | key | $@ is used to sign a JWT token. | main.go:97:16:97:21 | "key8" | Hardcoded String | -| main.go:108:16:108:24 | sharedKey | main.go:107:22:107:27 | "key9" : string | main.go:108:16:108:24 | sharedKey | $@ is used to sign a JWT token. | main.go:107:22:107:27 | "key9" | Hardcoded String | -| main.go:114:16:114:30 | sharedKeyglobal | main.go:111:30:111:36 | "key10" : string | main.go:114:16:114:30 | sharedKeyglobal | $@ is used to sign a JWT token. | main.go:111:30:111:36 | "key10" | Hardcoded String | +| main.go:102:30:102:32 | key | main.go:97:16:97:21 | "key8" : string | main.go:102:30:102:32 | key | $@ is used to sign a JWT token. | main.go:97:16:97:21 | "key8" | Hardcoded String | +| main.go:107:16:107:24 | sharedKey | main.go:106:22:106:27 | "key9" : string | main.go:107:16:107:24 | sharedKey | $@ is used to sign a JWT token. | main.go:106:22:106:27 | "key9" | Hardcoded String | +| main.go:113:16:113:30 | sharedKeyglobal | main.go:110:30:110:36 | "key10" : string | main.go:113:16:113:30 | sharedKeyglobal | $@ is used to sign a JWT token. | main.go:110:30:110:36 | "key10" | Hardcoded String | +| sanitizer.go:18:44:18:46 | key | sanitizer.go:17:16:17:20 | `key` : string | sanitizer.go:18:44:18:46 | key | $@ is used to sign a JWT token. | sanitizer.go:17:16:17:20 | `key` | Hardcoded String | +| sanitizer.go:104:44:104:47 | key4 | sanitizer.go:80:10:80:14 | "asd" : string | sanitizer.go:104:44:104:47 | key4 | $@ is used to sign a JWT token. | sanitizer.go:80:10:80:14 | "asd" | Hardcoded String | diff --git a/go/ql/test/experimental/CWE-321/main.go b/go/ql/test/experimental/CWE-321/main.go index 5f2c5b6f7486..e966b34b62a2 100644 --- a/go/ql/test/experimental/CWE-321/main.go +++ b/go/ql/test/experimental/CWE-321/main.go @@ -7,7 +7,7 @@ package main //go:generate depstubber -vendor github.com/lestrrat/go-jwx/jwk "" New //go:generate depstubber -vendor github.com/square/go-jose/v3 Recipient NewEncrypter,NewSigner //go:generate depstubber -vendor gopkg.in/square/go-jose.v2 Recipient NewEncrypter,NewSigner -////go:generate depstubber -vendor github.com/cristalhq/jwt/v3 Signer NewSignerHS,HS256 +//go:generate depstubber -vendor github.com/cristalhq/jwt/v3 Signer NewSignerHS,HS256 import ( "time" @@ -98,7 +98,6 @@ func go_kit() interface{} { mapClaims = gjwt.MapClaims{"user": "go-kit"} ) - // e := func(ctx context.Context, i interface{}) (interface{}, error) { return ctx, nil } return gokit.NewSigner(kid, key, nil, mapClaims) // BAD } From ae2bc1b410527e35c80c8367b848a2e984f17d78 Mon Sep 17 00:00:00 2001 From: Porcupiney Hairs Date: Tue, 31 May 2022 23:10:57 +0530 Subject: [PATCH 03/11] Include suggested changes from review. --- .../experimental/CWE-321/HardcodedKeysLib.qll | 89 +++++++------ go/ql/test/experimental/CWE-321/sanitizer.go | 122 ++++++++++++++++++ 2 files changed, 175 insertions(+), 36 deletions(-) create mode 100644 go/ql/test/experimental/CWE-321/sanitizer.go diff --git a/go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll b/go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll index 027f42e6187c..0d5953517a0b 100644 --- a/go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll +++ b/go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll @@ -46,7 +46,7 @@ module HardcodedKeys { /** * A hardcoded string literal as a source for JWT token signing vulnerabilities. */ - class HardcodedStringSource extends Source { + private class HardcodedStringSource extends Source { HardcodedStringSource() { this.asExpr() instanceof StringLit and not (isTestCode(this.asExpr()) or isDemoCode(this.asExpr())) @@ -166,7 +166,7 @@ module HardcodedKeys { } /** Mark an empty string returned with an error as a sanitizer */ - class EmptyErrorSanitizer extends Sanitizer { + private class EmptyErrorSanitizer extends Sanitizer { EmptyErrorSanitizer() { exists(ReturnStmt r, DataFlow::CallNode c | c.getTarget().hasQualifiedName("errors", "New") and @@ -178,7 +178,7 @@ module HardcodedKeys { } /** Mark any formatting string call as a sanitizer */ - class FormattingSanitizer extends Sanitizer { + private class FormattingSanitizer extends Sanitizer { FormattingSanitizer() { exists(Formatting::StringFormatCall s | s.getAResult() = this) } } @@ -188,19 +188,6 @@ module HardcodedKeys { */ private class RandSliceSanitizer extends Sanitizer { RandSliceSanitizer() { - exists(DataFlow::CallNode randint, string name, DataFlow::ElementReadNode r | - ( - randint.getTarget().hasQualifiedName("math/rand", name) or - randint.getTarget().(Method).hasQualifiedName("math/rand", "Rand", name) - ) and - name = - [ - "ExpFloat64", "Float32", "Float64", "Int", "Int31", "Int31n", "Int63", "Int63n", "Intn", - "NormFloat64", "Uint32", "Uint64" - ] and - r.reads(this, randint.getAResult().getASuccessor*()) - ) - or // Sanitize flows like this: // func GenerateCryptoString(n int) (string, error) { // const chars = "123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-" @@ -215,12 +202,20 @@ module HardcodedKeys { // return string(ret), nil // } exists( - DataFlow::CallNode randint, DataFlow::MethodCallNode bigint, DataFlow::ElementReadNode r + DataFlow::CallNode randint, string name, DataFlow::ElementReadNode r, DataFlow::Node index | - randint.getTarget().hasQualifiedName("crypto/rand", "Int") and - bigint.getTarget().hasQualifiedName("math/big", "Int", "Int64") and - bigint.getReceiver() = randint.getResult(0).getASuccessor*() and - r.reads(this, bigint.getAResult().getASuccessor*()) + ( + randint.getTarget().hasQualifiedName("math/rand", name) or + randint.getTarget().(Method).hasQualifiedName("math/rand", "Rand", name) or + randint.getTarget().hasQualifiedName("crypto/rand", "Int") + ) and + name = + [ + "ExpFloat64", "Float32", "Float64", "Int", "Int31", "Int31n", "Int63", "Int63n", "Intn", + "NormFloat64", "Uint32", "Uint64" + ] and + TaintTracking::localTaint(randint.getAResult(), index) and + r.reads(this, index) ) or // Sanitize flows like : @@ -232,29 +227,49 @@ module HardcodedKeys { // } // return string(bytes) // } - exists(DataFlow::CallNode randread, DataFlow::Node rand, DataFlow::ElementReadNode r | + exists(DataFlow::CallNode randread, DataFlow::Node rand | randread.getTarget().hasQualifiedName("crypto/rand", "Read") and TaintTracking::localTaint(any(DataFlow::PostUpdateNode pun | pun.getPreUpdateNode() = randread.getArgument(0) ), rand) and - ( - // Flow through a ModExpr if any of the operands are tainted. - // For ex, in the case shown above, - // `bytes[i] = characters[x%byte(len(characters))]` - // given x is cryptographically secure random number, - // we can assume that `bytes` is random and cryptographically secure. - exists(ModExpr e | e.getAnOperand() = rand.asExpr() | - r.reads(this, e.getGlobalValueNumber().getANode()) - ) - or - // This is an alternative case where the code uses `x` directly instead - // `bytes[i] = characters[x]` - r.reads(this.getAPredecessor*(), rand) - ) + this.(DataFlow::ElementReadNode).reads(_, rand) ) } } + /** + * Models flow from a call to `Int64` if the receiver is tainted + */ + private class BigIntFlow extends TaintTracking::FunctionModel { + BigIntFlow() { this.(Method).hasQualifiedName("math/big", "Int", "Int64") } + + override predicate hasTaintFlow(DataFlow::FunctionInput inp, DataFlow::FunctionOutput outp) { + inp.isReceiver() and + outp.isResult(0) + } + } + + /* + * This is code is used to model taint flow through a binary operation such as a + * modulo `%` operation or an addition `+` operation + */ + + private class BinExpAdditionalTaintStep extends TaintTracking::AdditionalTaintStep { + // This is required to model the sanitizers for the `HardcodedKeys` query. + // This is required to correctly detect a sanitizer such as the one shown below. + // func GenerateRandomString(size int) string { + // var bytes = make([]byte, size) + // rand.Read(bytes) + // for i, x := range bytes { + // bytes[i] = characters[x%byte(len(characters))] + // } + // return string(bytes) + // } + override predicate step(DataFlow::Node prev, DataFlow::Node succ) { + exists(BinaryExpr b | b.getAnOperand() = prev.asExpr() | succ.asExpr() = b) + } + } + /** * A configuration depicting taint flow for studying JWT token signing vulnerabilities. */ @@ -267,6 +282,8 @@ module HardcodedKeys { override predicate isSanitizer(DataFlow::Node sanitizer) { sanitizer instanceof Sanitizer } + // override predicate isAdditionalTaintStep(DataFlow::Node prev, DataFlow::Node succ) { + // } override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { guard instanceof SanitizerGuard } diff --git a/go/ql/test/experimental/CWE-321/sanitizer.go b/go/ql/test/experimental/CWE-321/sanitizer.go new file mode 100644 index 000000000000..b79a1014554e --- /dev/null +++ b/go/ql/test/experimental/CWE-321/sanitizer.go @@ -0,0 +1,122 @@ +package main + +//go:generate depstubber -vendor github.com/cristalhq/jwt/v3 Signer NewSignerHS,HS256 + +import ( + crand "crypto/rand" + "errors" + "fmt" + "math/big" + "math/rand" + "time" + + cristal "github.com/cristalhq/jwt/v3" +) + +func cristalhq() (interface{}, error) { + key := []byte(`key`) + return cristal.NewSignerHS(cristal.HS256, key) // BAD +} + +func GenerateRandomString(size int) string { + const characters = `0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz` + var bytes = make([]byte, size) + crand.Read(bytes) + for i, x := range bytes { + bytes[i] = characters[x%byte(len(characters))] + } + return string(bytes) +} + +func GenerateCryptoString2(n int) (string, error) { + const chars = "123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-" + ret := make([]byte, n) + for i := range ret { + num, err := crand.Int(crand.Reader, big.NewInt(int64(len(chars)))) + if err != nil { + return "", err + } + ret[i] = chars[num.Int64()] + } + return string(ret), nil +} +func GenerateRandomString3(size int) string { + const characters = `0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz` + var bytes = make([]byte, size) + crand.Read(bytes) + for i, x := range bytes { + bytes[i] = characters[x] + } + return string(bytes) +} + +func RandAuthToken() string { + buf := make([]byte, 32) + _, err := crand.Read(buf) + if err != nil { + return RandString(64) + } + + return fmt.Sprintf("%x", buf) +} + +func RandString(length int64) string { + sources := []byte("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ") + var result []byte + r := rand.New(rand.NewSource(time.Now().UnixNano())) + sourceLength := len(sources) + var i int64 = 0 + for ; i < length; i++ { + result = append(result, sources[r.Intn(sourceLength)]) + } + + return string(result) +} +func genKey(size int) (string, error) { + if size < 10 { + err := errors.New("size too small") + return "", err + } else { + return "asd", nil + } +} +func test1() { + key := GenerateRandomString(32) + return cristal.NewSignerHS(cristal.HS256, key) // GOOD +} + +func test2() { + key2, _ := GenerateCryptoString2(32) + return cristal.NewSignerHS(cristal.HS256, key2) // GOOD +} + +func test3() { + key3 := RandAuthToken() + return cristal.NewSignerHS(cristal.HS256, key3) // GOOD +} + +func test4() (interface{}, error) { + key4, err := genKey(21) + if err != nil { + return nil, err + } + + return cristal.NewSignerHS(cristal.HS256, key4) // BAD +} + +func test5() (interface{}, error) { + temp := "test" + if temp != "test" { + return cristal.NewSignerHS(cristal.HS256, []byte(temp)), nil // GOOD + } else { + return nil, nil + } +} +func test6() { + key := GenerateRandomString3(32) + return cristal.NewSignerHS(cristal.HS256, key) // GOOD +} + +func main() { + return +} From 1ef42a11ad4a49439b171d629cfab7e631987aa9 Mon Sep 17 00:00:00 2001 From: Porcupiney Hairs Date: Thu, 2 Jun 2022 16:04:29 +0530 Subject: [PATCH 04/11] Include suggested changes from review. --- .../experimental/CWE-321/HardcodedKeysLib.qll | 98 ++++++++++--------- .../CWE-321/HardcodedKeys.expected | 6 -- go/ql/test/experimental/CWE-321/sanitizer.go | 8 +- 3 files changed, 54 insertions(+), 58 deletions(-) diff --git a/go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll b/go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll index 0d5953517a0b..66d3f86d9aae 100644 --- a/go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll +++ b/go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll @@ -182,57 +182,65 @@ module HardcodedKeys { FormattingSanitizer() { exists(Formatting::StringFormatCall s | s.getAResult() = this) } } + private string getRandIntFunctionName() { + result = + [ + "ExpFloat64", "Float32", "Float64", "Int", "Int31", "Int31n", "Int63", "Int63n", "Intn", + "NormFloat64", "Uint32", "Uint64" + ] + } + + private DataFlow::CallNode getARandIntCall() { + result.getTarget().hasQualifiedName("math/rand", getRandIntFunctionName()) or + result.getTarget().(Method).hasQualifiedName("math/rand", "Rand", getRandIntFunctionName()) or + result.getTarget().hasQualifiedName("crypto/rand", "Int") + } + + private DataFlow::CallNode getARandReadCall() { + result.getTarget().hasQualifiedName("crypto/rand", "Read") + } + /** * Mark any taint arising from a read on a tainted slice with a random index as a * sanitizer for all instances of the taint */ private class RandSliceSanitizer extends Sanitizer { RandSliceSanitizer() { - // Sanitize flows like this: - // func GenerateCryptoString(n int) (string, error) { - // const chars = "123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-" - // ret := make([]byte, n) - // for i := range ret { - // num, err := crand.Int(crand.Reader, big.NewInt(int64(len(chars)))) - // if err != nil { - // return "", err - // } - // ret[i] = chars[num.Int64()] - // } - // return string(ret), nil - // } - exists( - DataFlow::CallNode randint, string name, DataFlow::ElementReadNode r, DataFlow::Node index + exists(DataFlow::Node randomValue, DataFlow::Node index | + // Sanitize flows like this: + // func GenerateCryptoString(n int) (string, error) { + // const chars = "123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-" + // ret := make([]byte, n) + // for i := range ret { + // num, err := crand.Int(crand.Reader, big.NewInt(int64(len(chars)))) + // if err != nil { + // return "", err + // } + // ret[i] = chars[num.Int64()] + // } + // return string(ret), nil + // } + randomValue = getARandIntCall().getAResult() + or + // Sanitize flows like : + // func GenerateRandomString(size int) string { + // var bytes = make([]byte, size) + // rand.Read(bytes) + // for i, x := range bytes { + // bytes[i] = characters[x%byte(len(characters))] + // } + // return string(bytes) + // } + randomValue = + any(DataFlow::PostUpdateNode pun | + pun.getPreUpdateNode() = getARandReadCall().getArgument(0) + ) | + TaintTracking::localTaint(randomValue, index) and ( - randint.getTarget().hasQualifiedName("math/rand", name) or - randint.getTarget().(Method).hasQualifiedName("math/rand", "Rand", name) or - randint.getTarget().hasQualifiedName("crypto/rand", "Int") - ) and - name = - [ - "ExpFloat64", "Float32", "Float64", "Int", "Int31", "Int31n", "Int63", "Int63n", "Intn", - "NormFloat64", "Uint32", "Uint64" - ] and - TaintTracking::localTaint(randint.getAResult(), index) and - r.reads(this, index) - ) - or - // Sanitize flows like : - // func GenerateRandomString(size int) string { - // var bytes = make([]byte, size) - // rand.Read(bytes) - // for i, x := range bytes { - // bytes[i] = characters[x%byte(len(characters))] - // } - // return string(bytes) - // } - exists(DataFlow::CallNode randread, DataFlow::Node rand | - randread.getTarget().hasQualifiedName("crypto/rand", "Read") and - TaintTracking::localTaint(any(DataFlow::PostUpdateNode pun | - pun.getPreUpdateNode() = randread.getArgument(0) - ), rand) and - this.(DataFlow::ElementReadNode).reads(_, rand) + this.(DataFlow::ElementReadNode).reads(_, randomValue) or + any(DataFlow::ElementReadNode r).reads(this, index) + ) ) } } @@ -250,7 +258,7 @@ module HardcodedKeys { } /* - * This is code is used to model taint flow through a binary operation such as a + * Models taint flow through a binary operation such as a * modulo `%` operation or an addition `+` operation */ @@ -282,8 +290,6 @@ module HardcodedKeys { override predicate isSanitizer(DataFlow::Node sanitizer) { sanitizer instanceof Sanitizer } - // override predicate isAdditionalTaintStep(DataFlow::Node prev, DataFlow::Node succ) { - // } override predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { guard instanceof SanitizerGuard } diff --git a/go/ql/test/experimental/CWE-321/HardcodedKeys.expected b/go/ql/test/experimental/CWE-321/HardcodedKeys.expected index 696386398770..23b79ccb2a9d 100644 --- a/go/ql/test/experimental/CWE-321/HardcodedKeys.expected +++ b/go/ql/test/experimental/CWE-321/HardcodedKeys.expected @@ -22,8 +22,6 @@ edges | main.go:110:30:110:36 | "key10" : string | main.go:110:23:110:37 | type conversion : string | | sanitizer.go:17:9:17:21 | type conversion : string | sanitizer.go:18:44:18:46 | key | | sanitizer.go:17:16:17:20 | `key` : string | sanitizer.go:17:9:17:21 | type conversion : string | -| sanitizer.go:80:10:80:14 | "asd" : string | sanitizer.go:99:2:99:24 | ... := ...[0] : string | -| sanitizer.go:99:2:99:24 | ... := ...[0] : string | sanitizer.go:104:44:104:47 | key4 | nodes | HardcodedKeysBad.go:11:18:11:38 | type conversion : string | semmle.label | type conversion : string | | HardcodedKeysBad.go:11:25:11:37 | "AllYourBase" : string | semmle.label | "AllYourBase" : string | @@ -60,9 +58,6 @@ nodes | sanitizer.go:17:9:17:21 | type conversion : string | semmle.label | type conversion : string | | sanitizer.go:17:16:17:20 | `key` : string | semmle.label | `key` : string | | sanitizer.go:18:44:18:46 | key | semmle.label | key | -| sanitizer.go:80:10:80:14 | "asd" : string | semmle.label | "asd" : string | -| sanitizer.go:99:2:99:24 | ... := ...[0] : string | semmle.label | ... := ...[0] : string | -| sanitizer.go:104:44:104:47 | key4 | semmle.label | key4 | subpaths #select | HardcodedKeysBad.go:19:28:19:39 | mySigningKey | HardcodedKeysBad.go:11:25:11:37 | "AllYourBase" : string | HardcodedKeysBad.go:19:28:19:39 | mySigningKey | $@ is used to sign a JWT token. | HardcodedKeysBad.go:11:25:11:37 | "AllYourBase" | Hardcoded String | @@ -77,4 +72,3 @@ subpaths | main.go:107:16:107:24 | sharedKey | main.go:106:22:106:27 | "key9" : string | main.go:107:16:107:24 | sharedKey | $@ is used to sign a JWT token. | main.go:106:22:106:27 | "key9" | Hardcoded String | | main.go:113:16:113:30 | sharedKeyglobal | main.go:110:30:110:36 | "key10" : string | main.go:113:16:113:30 | sharedKeyglobal | $@ is used to sign a JWT token. | main.go:110:30:110:36 | "key10" | Hardcoded String | | sanitizer.go:18:44:18:46 | key | sanitizer.go:17:16:17:20 | `key` : string | sanitizer.go:18:44:18:46 | key | $@ is used to sign a JWT token. | sanitizer.go:17:16:17:20 | `key` | Hardcoded String | -| sanitizer.go:104:44:104:47 | key4 | sanitizer.go:80:10:80:14 | "asd" : string | sanitizer.go:104:44:104:47 | key4 | $@ is used to sign a JWT token. | sanitizer.go:80:10:80:14 | "asd" | Hardcoded String | diff --git a/go/ql/test/experimental/CWE-321/sanitizer.go b/go/ql/test/experimental/CWE-321/sanitizer.go index b79a1014554e..4b18acc504a4 100644 --- a/go/ql/test/experimental/CWE-321/sanitizer.go +++ b/go/ql/test/experimental/CWE-321/sanitizer.go @@ -73,12 +73,8 @@ func RandString(length int64) string { return string(result) } func genKey(size int) (string, error) { - if size < 10 { - err := errors.New("size too small") - return "", err - } else { - return "asd", nil - } + err := errors.New("size too small") + return "", err } func test1() { key := GenerateRandomString(32) From 361b7037c6f2e5d0aed28c593c9dd303f82d240b Mon Sep 17 00:00:00 2001 From: Porcupiney Hairs Date: Thu, 2 Jun 2022 19:11:44 +0530 Subject: [PATCH 05/11] Include suggested changes from review. --- go/ql/test/experimental/CWE-321/main.go | 8 --- go/ql/test/experimental/CWE-321/sanitizer.go | 52 ++++++++++---------- 2 files changed, 26 insertions(+), 34 deletions(-) diff --git a/go/ql/test/experimental/CWE-321/main.go b/go/ql/test/experimental/CWE-321/main.go index e966b34b62a2..1e1f3ee45e4b 100644 --- a/go/ql/test/experimental/CWE-321/main.go +++ b/go/ql/test/experimental/CWE-321/main.go @@ -113,14 +113,6 @@ func lejwt2() (interface{}, error) { return le.New(sharedKeyglobal) // BAD } -func BarrierGuardTest() (interface{}, error) { - sharedKey := "" - if sharedKey != "" { - return le.New([]byte(sharedKey)) // GOOD - } - return "", nil -} - func main() { return } diff --git a/go/ql/test/experimental/CWE-321/sanitizer.go b/go/ql/test/experimental/CWE-321/sanitizer.go index 4b18acc504a4..890172c80cd4 100644 --- a/go/ql/test/experimental/CWE-321/sanitizer.go +++ b/go/ql/test/experimental/CWE-321/sanitizer.go @@ -13,7 +13,7 @@ import ( cristal "github.com/cristalhq/jwt/v3" ) -func cristalhq() (interface{}, error) { +func check_ok() (interface{}, error) { key := []byte(`key`) return cristal.NewSignerHS(cristal.HS256, key) // BAD } @@ -40,6 +40,7 @@ func GenerateCryptoString2(n int) (string, error) { } return string(ret), nil } + func GenerateRandomString3(size int) string { const characters = `0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz` var bytes = make([]byte, size) @@ -72,45 +73,44 @@ func RandString(length int64) string { return string(result) } -func genKey(size int) (string, error) { - err := errors.New("size too small") - return "", err -} -func test1() { + +func randIntSanitizerModulo_test() (interface{}, error) { key := GenerateRandomString(32) - return cristal.NewSignerHS(cristal.HS256, key) // GOOD + return cristal.NewSignerHS(cristal.HS256, []byte(key)) // GOOD } -func test2() { +func randIntSanitizer_test() (interface{}, error) { key2, _ := GenerateCryptoString2(32) - return cristal.NewSignerHS(cristal.HS256, key2) // GOOD + return cristal.NewSignerHS(cristal.HS256, []byte(key2)) // GOOD } -func test3() { +func formattingSanitizer_test() (interface{}, error) { key3 := RandAuthToken() - return cristal.NewSignerHS(cristal.HS256, key3) // GOOD + return cristal.NewSignerHS(cristal.HS256, []byte(key3)) // GOOD } -func test4() (interface{}, error) { - key4, err := genKey(21) - if err != nil { - return nil, err - } +func genKey() (string, error) { + k := "asd" + e := errors.New("no key") + return k, e +} - return cristal.NewSignerHS(cristal.HS256, key4) // BAD +func emptyErrorSanitizer_test() (interface{}, error) { + key4, _ := genKey() + return cristal.NewSignerHS(cristal.HS256, []byte(key4)) // GOOD } -func test5() (interface{}, error) { - temp := "test" - if temp != "test" { - return cristal.NewSignerHS(cristal.HS256, []byte(temp)), nil // GOOD - } else { - return nil, nil +func compareSanitizerTest() (interface{}, error) { + key5 := "" + if key5 != "" { + return cristal.NewSignerHS(cristal.HS256, []byte(key5)) // GOOD } + return "", nil } -func test6() { - key := GenerateRandomString3(32) - return cristal.NewSignerHS(cristal.HS256, key) // GOOD + +func randReadSanitizer_test() (interface{}, error) { + key6 := GenerateRandomString3(32) + return cristal.NewSignerHS(cristal.HS256, []byte(key6)) // GOOD } func main() { From bfbc1d48b7811decb22a0566cac53119cee28077 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Thu, 2 Jun 2022 15:02:41 +0100 Subject: [PATCH 06/11] Simplify redundant sanitizer --- go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll b/go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll index 66d3f86d9aae..80ea30fc41a1 100644 --- a/go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll +++ b/go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll @@ -237,10 +237,7 @@ module HardcodedKeys { ) | TaintTracking::localTaint(randomValue, index) and - ( - this.(DataFlow::ElementReadNode).reads(_, randomValue) or - any(DataFlow::ElementReadNode r).reads(this, index) - ) + this.(DataFlow::ElementReadNode).reads(_, index) ) } } From 3155771abe44cafaac642cb3321c9fb780f8536c Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Thu, 2 Jun 2022 15:10:02 +0100 Subject: [PATCH 07/11] Rename empty-string sanitizer to reflect what it actually does. --- go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll b/go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll index 80ea30fc41a1..9342573e89e2 100644 --- a/go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll +++ b/go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll @@ -165,9 +165,15 @@ module HardcodedKeys { } } - /** Mark an empty string returned with an error as a sanitizer */ - private class EmptyErrorSanitizer extends Sanitizer { - EmptyErrorSanitizer() { + /** + * Marks anything returned with an error as a sanitized. + * + * Typically this means contexts like `return "", errors.New("Oh no")`, + * where we can be reasonably confident downstream users won't mistake + * that empty string for a usable key. + */ + private class ReturnedAlongsideErrorSanitizer extends Sanitizer { + ReturnedAlongsideErrorSanitizer() { exists(ReturnStmt r, DataFlow::CallNode c | c.getTarget().hasQualifiedName("errors", "New") and r.getNumChild() > 1 and From b48a07e7b82484d7df2d087d6f963bc743d3ccdd Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Thu, 2 Jun 2022 15:18:38 +0100 Subject: [PATCH 08/11] Tighten up CompareExprSanitizer - Document - Only actually consider comparisons - Don't sanitize literals --- go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll b/go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll index 9342573e89e2..d4aca848f558 100644 --- a/go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll +++ b/go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll @@ -154,13 +154,18 @@ module HardcodedKeys { } /** - * Mark any comparision expression where any operand is tainted as a - * sanitizer for all instances of the taint + * Sanitizes any other use of an operand to a comparison, on the assumption that this may filter + * out special constant values -- for example, in context `if key != "invalid_key" { ... }`, + * if `"invalid_key"` is indeed the only dangerous key then guarded uses of `key` are likely + * to be safe. + * + * TODO: Before promoting this query look at replacing this with something more principled. */ private class CompareExprSanitizer extends Sanitizer { CompareExprSanitizer() { - exists(BinaryExpr c | - c.getAnOperand().getGlobalValueNumber() = this.asExpr().getGlobalValueNumber() + exists(ComparisonExpr c | + c.getAnOperand().getGlobalValueNumber() = this.asExpr().getGlobalValueNumber() and + not this.asExpr() instanceof Literal ) } } From 602495df4c1362ce03c091299bb7049cf5eee194 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Thu, 2 Jun 2022 15:53:41 +0100 Subject: [PATCH 09/11] Replace cases accidentally handled by CompareExprSanitizer with ReturnedAlongsideErrorSanitizerGuard --- .../experimental/CWE-321/HardcodedKeysLib.qll | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll b/go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll index d4aca848f558..d6d9c77ad090 100644 --- a/go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll +++ b/go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll @@ -188,6 +188,26 @@ module HardcodedKeys { } } + /** + * Marks anything returned alongside an error-value that is known + * to be non-nil by virtue of a guarding check as harmless. + * + * For example, `if err != nil { return "", err }` is unlikely to be + * contributing a dangerous hardcoded key. + */ + private class ReturnedAlongsideErrorSanitizerGuard extends Sanitizer { + + ReturnedAlongsideErrorSanitizerGuard() { + exists(ControlFlow::ConditionGuardNode guard, SsaWithFields errorVar, ReturnStmt r | + guard.ensuresNeq(errorVar.getAUse(), Builtin::nil().getARead()) and + guard.dominates(this.getBasicBlock()) and + r.getExpr(1) = errorVar.getAUse().asExpr() and + this.asExpr() = r.getExpr(0) + ) + } + + } + /** Mark any formatting string call as a sanitizer */ private class FormattingSanitizer extends Sanitizer { FormattingSanitizer() { exists(Formatting::StringFormatCall s | s.getAResult() = this) } From e54b29a84676c6dcfaa59240a6090a4c8029f91f Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Thu, 2 Jun 2022 15:58:29 +0100 Subject: [PATCH 10/11] Autoformat --- go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll | 2 -- 1 file changed, 2 deletions(-) diff --git a/go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll b/go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll index d6d9c77ad090..2eef4108bf6f 100644 --- a/go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll +++ b/go/ql/src/experimental/CWE-321/HardcodedKeysLib.qll @@ -196,7 +196,6 @@ module HardcodedKeys { * contributing a dangerous hardcoded key. */ private class ReturnedAlongsideErrorSanitizerGuard extends Sanitizer { - ReturnedAlongsideErrorSanitizerGuard() { exists(ControlFlow::ConditionGuardNode guard, SsaWithFields errorVar, ReturnStmt r | guard.ensuresNeq(errorVar.getAUse(), Builtin::nil().getARead()) and @@ -205,7 +204,6 @@ module HardcodedKeys { this.asExpr() = r.getExpr(0) ) } - } /** Mark any formatting string call as a sanitizer */ From d5ac7190cc8203449f6471aa26b285db3c8f78e8 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Thu, 2 Jun 2022 17:02:54 +0100 Subject: [PATCH 11/11] Remove duplicate function --- go/ql/test/experimental/CWE-321/sanitizer.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/go/ql/test/experimental/CWE-321/sanitizer.go b/go/ql/test/experimental/CWE-321/sanitizer.go index 890172c80cd4..314d91870454 100644 --- a/go/ql/test/experimental/CWE-321/sanitizer.go +++ b/go/ql/test/experimental/CWE-321/sanitizer.go @@ -112,7 +112,3 @@ func randReadSanitizer_test() (interface{}, error) { key6 := GenerateRandomString3(32) return cristal.NewSignerHS(cristal.HS256, []byte(key6)) // GOOD } - -func main() { - return -}