From bf103da519903f8cb2256ed42f8002fb33c1086f Mon Sep 17 00:00:00 2001 From: Grant Murphy Date: Sun, 13 Nov 2016 12:55:31 -0800 Subject: [PATCH 1/2] Allow rules to register against multiple ast nodes Update the AddRule interface to allow rules to register interest in multiple ast.Nodes. Adds more flexibility to how rules can work, and was needed to fix the hard coded credentials test specifically. --- core/analyzer.go | 14 ++++++++------ rulelist.go | 2 +- rules/bind.go | 8 +++----- rules/blacklist.go | 34 +++++++++++++--------------------- rules/errors.go | 8 +++----- rules/fileperms.go | 8 ++++---- rules/httpoxy_test.go | 2 +- rules/rand.go | 8 +++----- rules/rsa.go | 8 +++----- rules/sql.go | 16 ++++++---------- rules/subproc.go | 8 +++----- rules/tempfiles.go | 8 +++----- rules/templates.go | 8 +++----- rules/tls.go | 24 +++++++++--------------- rules/unsafe.go | 11 ++++------- rules/weakcrypto.go | 4 ++-- 16 files changed, 69 insertions(+), 102 deletions(-) diff --git a/core/analyzer.go b/core/analyzer.go index 41904aa..0fa8a48 100644 --- a/core/analyzer.go +++ b/core/analyzer.go @@ -142,12 +142,14 @@ func (gas *Analyzer) process(filename string, source interface{}) error { // AddRule adds a rule into a rule set list mapped to the given AST node's type. // The node is only needed for its type and is not otherwise used. -func (gas *Analyzer) AddRule(r Rule, n ast.Node) { - t := reflect.TypeOf(n) - if val, ok := gas.ruleset[t]; ok { - gas.ruleset[t] = append(val, r) - } else { - gas.ruleset[t] = []Rule{r} +func (gas *Analyzer) AddRule(r Rule, nodes []ast.Node) { + for _, n := range nodes { + t := reflect.TypeOf(n) + if val, ok := gas.ruleset[t]; ok { + gas.ruleset[t] = append(val, r) + } else { + gas.ruleset[t] = []Rule{r} + } } } diff --git a/rulelist.go b/rulelist.go index 61ea56f..0c207af 100644 --- a/rulelist.go +++ b/rulelist.go @@ -23,7 +23,7 @@ import ( type RuleInfo struct { description string - build func(map[string]interface{}) (gas.Rule, ast.Node) + build func(map[string]interface{}) (gas.Rule, []ast.Node) } // GetFullRuleList get the full list of all rules available to GAS diff --git a/rules/bind.go b/rules/bind.go index 4363684..c2fa781 100644 --- a/rules/bind.go +++ b/rules/bind.go @@ -39,8 +39,8 @@ func (r *BindsToAllNetworkInterfaces) Match(n ast.Node, c *gas.Context) (gi *gas return } -func NewBindsToAllNetworkInterfaces(conf map[string]interface{}) (r gas.Rule, n ast.Node) { - r = &BindsToAllNetworkInterfaces{ +func NewBindsToAllNetworkInterfaces(conf map[string]interface{}) (gas.Rule, []ast.Node) { + return &BindsToAllNetworkInterfaces{ call: regexp.MustCompile(`^net\.Listen$`), pattern: regexp.MustCompile(`^(0.0.0.0|:).*$`), MetaData: gas.MetaData{ @@ -48,7 +48,5 @@ func NewBindsToAllNetworkInterfaces(conf map[string]interface{}) (r gas.Rule, n Confidence: gas.High, What: "Binds to all network interfaces", }, - } - n = (*ast.CallExpr)(nil) - return + }, []ast.Node{(*ast.CallExpr)(nil)} } diff --git a/rules/blacklist.go b/rules/blacklist.go index f3ceb39..747eb4b 100644 --- a/rules/blacklist.go +++ b/rules/blacklist.go @@ -34,54 +34,46 @@ func (r *BlacklistImport) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err return nil, nil } -func NewBlacklist_crypto_md5(conf map[string]interface{}) (r gas.Rule, n ast.Node) { - r = &BlacklistImport{ +func NewBlacklist_crypto_md5(conf map[string]interface{}) (gas.Rule, []ast.Node) { + return &BlacklistImport{ MetaData: gas.MetaData{ Severity: gas.High, Confidence: gas.High, What: "Use of weak cryptographic primitive", }, Path: `"crypto/md5"`, - } - n = (*ast.ImportSpec)(nil) - return + }, []ast.Node{(*ast.ImportSpec)(nil)} } -func NewBlacklist_crypto_des(conf map[string]interface{}) (r gas.Rule, n ast.Node) { - r = &BlacklistImport{ +func NewBlacklist_crypto_des(conf map[string]interface{}) (gas.Rule, []ast.Node) { + return &BlacklistImport{ MetaData: gas.MetaData{ Severity: gas.High, Confidence: gas.High, What: "Use of weak cryptographic primitive", }, Path: `"crypto/des"`, - } - n = (*ast.ImportSpec)(nil) - return + }, []ast.Node{(*ast.ImportSpec)(nil)} } -func NewBlacklist_crypto_rc4(conf map[string]interface{}) (r gas.Rule, n ast.Node) { - r = &BlacklistImport{ +func NewBlacklist_crypto_rc4(conf map[string]interface{}) (gas.Rule, []ast.Node) { + return &BlacklistImport{ MetaData: gas.MetaData{ Severity: gas.High, Confidence: gas.High, What: "Use of weak cryptographic primitive", }, Path: `"crypto/rc4"`, - } - n = (*ast.ImportSpec)(nil) - return + }, []ast.Node{(*ast.ImportSpec)(nil)} } -func NewBlacklist_net_http_cgi(conf map[string]interface{}) (r gas.Rule, n ast.Node) { - r = &BlacklistImport{ +func NewBlacklist_net_http_cgi(conf map[string]interface{}) (gas.Rule, []ast.Node) { + return &BlacklistImport{ MetaData: gas.MetaData{ Severity: gas.High, Confidence: gas.High, - What: "Go code running under CGI is vulnerable to Httpoxy attack. (CVE-2016-5386)", + What: "Go versions < 1.6.3 are vulnerable to Httpoxy attack: (CVE-2016-5386)", }, Path: `"net/http/cgi"`, - } - n = (*ast.ImportSpec)(nil) - return + }, []ast.Node{(*ast.ImportSpec)(nil)} } diff --git a/rules/errors.go b/rules/errors.go index 8d74634..4490312 100644 --- a/rules/errors.go +++ b/rules/errors.go @@ -50,14 +50,12 @@ func (r *NoErrorCheck) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err err return nil, nil } -func NewNoErrorCheck(conf map[string]interface{}) (r gas.Rule, n ast.Node) { - r = &NoErrorCheck{ +func NewNoErrorCheck(conf map[string]interface{}) (gas.Rule, []ast.Node) { + return &NoErrorCheck{ MetaData: gas.MetaData{ Severity: gas.Low, Confidence: gas.High, What: "Errors unhandled.", }, - } - n = (*ast.AssignStmt)(nil) - return + }, []ast.Node{(*ast.AssignStmt)(nil)} } diff --git a/rules/fileperms.go b/rules/fileperms.go index 061876d..9a812cb 100644 --- a/rules/fileperms.go +++ b/rules/fileperms.go @@ -52,7 +52,7 @@ func (r *FilePermissions) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) return nil, nil } -func NewFilePerms(conf map[string]interface{}) (gas.Rule, ast.Node) { +func NewFilePerms(conf map[string]interface{}) (gas.Rule, []ast.Node) { mode := getConfiguredMode(conf, "G302", 0600) return &FilePermissions{ mode: mode, @@ -63,10 +63,10 @@ func NewFilePerms(conf map[string]interface{}) (gas.Rule, ast.Node) { Confidence: gas.High, What: fmt.Sprintf("Expect file permissions to be %#o or less", mode), }, - }, (*ast.CallExpr)(nil) + }, []ast.Node{(*ast.CallExpr)(nil)} } -func NewMkdirPerms(conf map[string]interface{}) (gas.Rule, ast.Node) { +func NewMkdirPerms(conf map[string]interface{}) (gas.Rule, []ast.Node) { mode := getConfiguredMode(conf, "G301", 0700) return &FilePermissions{ mode: mode, @@ -77,5 +77,5 @@ func NewMkdirPerms(conf map[string]interface{}) (gas.Rule, ast.Node) { Confidence: gas.High, What: fmt.Sprintf("Expect directory permissions to be %#o or less", mode), }, - }, (*ast.CallExpr)(nil) + }, []ast.Node{(*ast.CallExpr)(nil)} } diff --git a/rules/httpoxy_test.go b/rules/httpoxy_test.go index 758389f..690794e 100644 --- a/rules/httpoxy_test.go +++ b/rules/httpoxy_test.go @@ -32,5 +32,5 @@ func TestHttpoxy(t *testing.T) { ) func main() {}`, analyzer) - checkTestResults(t, issues, 1, "Go code running under CGI is vulnerable to Httpoxy attack.") + checkTestResults(t, issues, 1, "Go versions < 1.6.3 are vulnerable to Httpoxy") } diff --git a/rules/rand.go b/rules/rand.go index 54b6e6c..47ac55d 100644 --- a/rules/rand.go +++ b/rules/rand.go @@ -34,8 +34,8 @@ func (w *WeakRand) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) { return nil, nil } -func NewWeakRandCheck(conf map[string]interface{}) (r gas.Rule, n ast.Node) { - r = &WeakRand{ +func NewWeakRandCheck(conf map[string]interface{}) (gas.Rule, []ast.Node) { + return &WeakRand{ funcName: "Read", packagePath: "math/rand", MetaData: gas.MetaData{ @@ -43,7 +43,5 @@ func NewWeakRandCheck(conf map[string]interface{}) (r gas.Rule, n ast.Node) { Confidence: gas.Medium, What: "Use of weak random number generator (math/rand instead of crypto/rand)", }, - } - n = (*ast.CallExpr)(nil) - return + }, []ast.Node{(*ast.CallExpr)(nil)} } diff --git a/rules/rsa.go b/rules/rsa.go index 5872186..510ca78 100644 --- a/rules/rsa.go +++ b/rules/rsa.go @@ -37,9 +37,9 @@ func (w *WeakKeyStrength) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) return nil, nil } -func NewWeakKeyStrength(conf map[string]interface{}) (r gas.Rule, n ast.Node) { +func NewWeakKeyStrength(conf map[string]interface{}) (gas.Rule, []ast.Node) { bits := 2048 - r = &WeakKeyStrength{ + return &WeakKeyStrength{ pattern: regexp.MustCompile(`^rsa\.GenerateKey$`), bits: bits, MetaData: gas.MetaData{ @@ -47,7 +47,5 @@ func NewWeakKeyStrength(conf map[string]interface{}) (r gas.Rule, n ast.Node) { Confidence: gas.High, What: fmt.Sprintf("RSA keys should be at least %d bits", bits), }, - } - n = (*ast.CallExpr)(nil) - return + }, []ast.Node{(*ast.CallExpr)(nil)} } diff --git a/rules/sql.go b/rules/sql.go index 18483d6..10db0a2 100644 --- a/rules/sql.go +++ b/rules/sql.go @@ -56,8 +56,8 @@ func (s *SqlStrConcat) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) { return nil, nil } -func NewSqlStrConcat(conf map[string]interface{}) (r gas.Rule, n ast.Node) { - r = &SqlStrConcat{ +func NewSqlStrConcat(conf map[string]interface{}) (gas.Rule, []ast.Node) { + return &SqlStrConcat{ SqlStatement: SqlStatement{ pattern: regexp.MustCompile(`(?)(SELECT|DELETE|INSERT|UPDATE|INTO|FROM|WHERE) `), MetaData: gas.MetaData{ @@ -66,9 +66,7 @@ func NewSqlStrConcat(conf map[string]interface{}) (r gas.Rule, n ast.Node) { What: "SQL string concatenation", }, }, - } - n = (*ast.BinaryExpr)(nil) - return + }, []ast.Node{(*ast.BinaryExpr)(nil)} } type SqlStrFormat struct { @@ -86,8 +84,8 @@ func (s *SqlStrFormat) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err err return nil, nil } -func NewSqlStrFormat(conf map[string]interface{}) (r gas.Rule, n ast.Node) { - r = &SqlStrFormat{ +func NewSqlStrFormat(conf map[string]interface{}) (gas.Rule, []ast.Node) { + return &SqlStrFormat{ call: regexp.MustCompile(`^fmt\.Sprintf$`), SqlStatement: SqlStatement{ pattern: regexp.MustCompile("(?)(SELECT|DELETE|INSERT|UPDATE|INTO|FROM|WHERE) "), @@ -97,7 +95,5 @@ func NewSqlStrFormat(conf map[string]interface{}) (r gas.Rule, n ast.Node) { What: "SQL string formatting", }, }, - } - n = (*ast.CallExpr)(nil) - return + }, []ast.Node{(*ast.CallExpr)(nil)} } diff --git a/rules/subproc.go b/rules/subproc.go index 991bbe2..b5a6fa2 100644 --- a/rules/subproc.go +++ b/rules/subproc.go @@ -49,10 +49,8 @@ func (r *Subprocess) Match(n ast.Node, c *gas.Context) (*gas.Issue, error) { return nil, nil } -func NewSubproc(conf map[string]interface{}) (r gas.Rule, n ast.Node) { - r = &Subprocess{ +func NewSubproc(conf map[string]interface{}) (gas.Rule, []ast.Node) { + return &Subprocess{ pattern: regexp.MustCompile(`^exec\.Command|syscall\.Exec$`), - } - n = (*ast.CallExpr)(nil) - return + }, []ast.Node{(*ast.CallExpr)(nil)} } diff --git a/rules/tempfiles.go b/rules/tempfiles.go index 7ca7570..3d2f49e 100644 --- a/rules/tempfiles.go +++ b/rules/tempfiles.go @@ -36,8 +36,8 @@ func (t *BadTempFile) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err erro return nil, nil } -func NewBadTempFile(conf map[string]interface{}) (r gas.Rule, n ast.Node) { - r = &BadTempFile{ +func NewBadTempFile(conf map[string]interface{}) (gas.Rule, []ast.Node) { + return &BadTempFile{ call: regexp.MustCompile(`ioutil\.WriteFile|os\.Create`), args: regexp.MustCompile(`^/tmp/.*$|^/var/tmp/.*$`), MetaData: gas.MetaData{ @@ -45,7 +45,5 @@ func NewBadTempFile(conf map[string]interface{}) (r gas.Rule, n ast.Node) { Confidence: gas.High, What: "File creation in shared tmp directory without using ioutil.Tempfile", }, - } - n = (*ast.CallExpr)(nil) - return + }, []ast.Node{(*ast.CallExpr)(nil)} } diff --git a/rules/templates.go b/rules/templates.go index 6b06a63..0f1dc24 100644 --- a/rules/templates.go +++ b/rules/templates.go @@ -37,15 +37,13 @@ func (t *TemplateCheck) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err er return nil, nil } -func NewTemplateCheck(conf map[string]interface{}) (r gas.Rule, n ast.Node) { - r = &TemplateCheck{ +func NewTemplateCheck(conf map[string]interface{}) (gas.Rule, []ast.Node) { + return &TemplateCheck{ call: regexp.MustCompile(`^template\.(HTML|JS|URL)$`), MetaData: gas.MetaData{ Severity: gas.Medium, Confidence: gas.Low, What: "this method will not auto-escape HTML. Verify data is well formed.", }, - } - n = (*ast.CallExpr)(nil) - return + }, []ast.Node{(*ast.CallExpr)(nil)} } diff --git a/rules/tls.go b/rules/tls.go index 301d3d9..c95fa58 100644 --- a/rules/tls.go +++ b/rules/tls.go @@ -109,9 +109,9 @@ func (t *InsecureConfigTLS) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, er return } -func NewModernTlsCheck(conf map[string]interface{}) (r gas.Rule, n ast.Node) { +func NewModernTlsCheck(conf map[string]interface{}) (gas.Rule, []ast.Node) { // https://wiki.mozilla.org/Security/Server_Side_TLS#Modern_compatibility - r = &InsecureConfigTLS{ + return &InsecureConfigTLS{ pattern: regexp.MustCompile(`^tls\.Config$`), MinVersion: 0x0303, // TLS 1.2 only MaxVersion: 0x0303, @@ -121,14 +121,12 @@ func NewModernTlsCheck(conf map[string]interface{}) (r gas.Rule, n ast.Node) { "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", }, - } - n = (*ast.CompositeLit)(nil) - return + }, []ast.Node{(*ast.CompositeLit)(nil)} } -func NewIntermediateTlsCheck(conf map[string]interface{}) (r gas.Rule, n ast.Node) { +func NewIntermediateTlsCheck(conf map[string]interface{}) (gas.Rule, []ast.Node) { // https://wiki.mozilla.org/Security/Server_Side_TLS#Intermediate_compatibility_.28default.29 - r = &InsecureConfigTLS{ + return &InsecureConfigTLS{ pattern: regexp.MustCompile(`^tls\.Config$`), MinVersion: 0x0301, // TLS 1.2, 1.1, 1.0 MaxVersion: 0x0303, @@ -149,14 +147,12 @@ func NewIntermediateTlsCheck(conf map[string]interface{}) (r gas.Rule, n ast.Nod "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", }, - } - n = (*ast.CompositeLit)(nil) - return + }, []ast.Node{(*ast.CompositeLit)(nil)} } -func NewCompatTlsCheck(conf map[string]interface{}) (r gas.Rule, n ast.Node) { +func NewCompatTlsCheck(conf map[string]interface{}) (gas.Rule, []ast.Node) { // https://wiki.mozilla.org/Security/Server_Side_TLS#Old_compatibility_.28default.29 - r = &InsecureConfigTLS{ + return &InsecureConfigTLS{ pattern: regexp.MustCompile(`^tls\.Config$`), MinVersion: 0x0301, // TLS 1.2, 1.1, 1.0 MaxVersion: 0x0303, @@ -179,7 +175,5 @@ func NewCompatTlsCheck(conf map[string]interface{}) (r gas.Rule, n ast.Node) { "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", }, - } - n = (*ast.CompositeLit)(nil) - return + }, []ast.Node{(*ast.CompositeLit)(nil)} } diff --git a/rules/unsafe.go b/rules/unsafe.go index 381f31f..3110727 100644 --- a/rules/unsafe.go +++ b/rules/unsafe.go @@ -15,10 +15,9 @@ package rules import ( + gas "github.com/GoASTScanner/gas/core" "go/ast" "regexp" - - gas "github.com/GoASTScanner/gas/core" ) type UsingUnsafe struct { @@ -33,15 +32,13 @@ func (r *UsingUnsafe) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err erro return nil, nil } -func NewUsingUnsafe(conf map[string]interface{}) (r gas.Rule, n ast.Node) { - r = &UsingUnsafe{ +func NewUsingUnsafe(conf map[string]interface{}) (gas.Rule, []ast.Node) { + return &UsingUnsafe{ pattern: regexp.MustCompile(`unsafe\..*`), MetaData: gas.MetaData{ What: "Use of unsafe calls should be audited", Severity: gas.Low, Confidence: gas.High, }, - } - n = (*ast.CallExpr)(nil) - return + }, []ast.Node{(*ast.CallExpr)(nil)} } diff --git a/rules/weakcrypto.go b/rules/weakcrypto.go index a10de70..1c859e9 100644 --- a/rules/weakcrypto.go +++ b/rules/weakcrypto.go @@ -36,7 +36,7 @@ func (r *UsesWeakCryptography) Match(n ast.Node, c *gas.Context) (*gas.Issue, er } // Uses des.* md5.* or rc4.* -func NewUsesWeakCryptography(conf map[string]interface{}) (gas.Rule, ast.Node) { +func NewUsesWeakCryptography(conf map[string]interface{}) (gas.Rule, []ast.Node) { calls := make(map[string][]string) calls["crypto/des"] = []string{"NewCipher", "NewTripleDESCipher"} calls["crypto/md5"] = []string{"New", "Sum"} @@ -49,5 +49,5 @@ func NewUsesWeakCryptography(conf map[string]interface{}) (gas.Rule, ast.Node) { What: "Use of weak cryptographic primitive", }, } - return rule, (*ast.CallExpr)(nil) + return rule, []ast.Node{(*ast.CallExpr)(nil)} } From a3fcd96f57246314004c9c0d0e747bfd29171e57 Mon Sep 17 00:00:00 2001 From: Grant Murphy Date: Sun, 13 Nov 2016 12:57:59 -0800 Subject: [PATCH 2/2] Update hardcoded credentials rule for GenDecls The hardcoded credentials rule will now also examine GenDecls so will work with global vars and constants. Fixes #74 --- rules/hardcoded_credentials.go | 68 ++++++++++++++++++++--------- rules/hardcoded_credentials_test.go | 40 +++++++++++++++++ 2 files changed, 88 insertions(+), 20 deletions(-) diff --git a/rules/hardcoded_credentials.go b/rules/hardcoded_credentials.go index 679749a..45a7993 100644 --- a/rules/hardcoded_credentials.go +++ b/rules/hardcoded_credentials.go @@ -15,43 +15,71 @@ package rules import ( - "go/ast" - "regexp" - gas "github.com/GoASTScanner/gas/core" + "go/ast" + "go/token" + "regexp" ) -type CredsAssign struct { +type Credentials struct { gas.MetaData pattern *regexp.Regexp } -func (r *CredsAssign) Match(n ast.Node, c *gas.Context) (gi *gas.Issue, err error) { - if node, ok := n.(*ast.AssignStmt); ok { - for _, i := range node.Lhs { - if ident, ok := i.(*ast.Ident); ok { - if r.pattern.MatchString(ident.Name) { - for _, e := range node.Rhs { - if _, ok := e.(*ast.BasicLit); ok { - return gas.NewIssue(c, n, r.What, r.Severity, r.Confidence), nil - } +func (r *Credentials) Match(n ast.Node, ctx *gas.Context) (*gas.Issue, error) { + switch node := n.(type) { + case *ast.AssignStmt: + return r.matchAssign(node, ctx) + case *ast.GenDecl: + return r.matchGenDecl(node, ctx) + } + return nil, nil +} + +func (r *Credentials) matchAssign(assign *ast.AssignStmt, ctx *gas.Context) (*gas.Issue, error) { + for _, i := range assign.Lhs { + if ident, ok := i.(*ast.Ident); ok { + if r.pattern.MatchString(ident.Name) { + for _, e := range assign.Rhs { + if _, ok := e.(*ast.BasicLit); ok { + return gas.NewIssue(ctx, assign, r.What, r.Severity, r.Confidence), nil } } } } } - return + return nil, nil } -func NewHardcodedCredentials(conf map[string]interface{}) (r gas.Rule, n ast.Node) { - r = &CredsAssign{ - pattern: regexp.MustCompile(`(?i)passwd|pass|password|pwd|secret|token`), +func (r *Credentials) matchGenDecl(decl *ast.GenDecl, ctx *gas.Context) (*gas.Issue, error) { + if decl.Tok != token.CONST && decl.Tok != token.VAR { + return nil, nil + } + for _, spec := range decl.Specs { + if valueSpec, ok := spec.(*ast.ValueSpec); ok { + for index, ident := range valueSpec.Names { + if r.pattern.MatchString(ident.Name) { + if _, ok := valueSpec.Values[index].(*ast.BasicLit); ok { + return gas.NewIssue(ctx, decl, r.What, r.Severity, r.Confidence), nil + } + } + } + } + } + return nil, nil +} + +func NewHardcodedCredentials(conf map[string]interface{}) (gas.Rule, []ast.Node) { + pattern := `(?i)passwd|pass|password|pwd|secret|token` + if val, ok := conf["G101"]; ok { + pattern = val.(string) + } + return &Credentials{ + pattern: regexp.MustCompile(pattern), MetaData: gas.MetaData{ What: "Potential hardcoded credentials", Confidence: gas.Low, Severity: gas.High, }, - } - n = (*ast.AssignStmt)(nil) - return + }, []ast.Node{(*ast.AssignStmt)(nil), (*ast.GenDecl)(nil)} } diff --git a/rules/hardcoded_credentials_test.go b/rules/hardcoded_credentials_test.go index c34c331..a7a2bd5 100644 --- a/rules/hardcoded_credentials_test.go +++ b/rules/hardcoded_credentials_test.go @@ -39,3 +39,43 @@ func TestHardcoded(t *testing.T) { checkTestResults(t, issues, 1, "Potential hardcoded credentials") } + +func TestHardcodedGlobalVar(t *testing.T) { + config := map[string]interface{}{"ignoreNosec": false} + analyzer := gas.NewAnalyzer(config, nil) + analyzer.AddRule(NewHardcodedCredentials(config)) + + issues := gasTestRunner(` + package samples + + import "fmt" + + var password = "admin" + + func main() { + username := "admin" + fmt.Println("Doing something with: ", username, password) + }`, analyzer) + + checkTestResults(t, issues, 1, "Potential hardcoded credentials") +} + +func TestHardcodedConstant(t *testing.T) { + config := map[string]interface{}{"ignoreNosec": false} + analyzer := gas.NewAnalyzer(config, nil) + analyzer.AddRule(NewHardcodedCredentials(config)) + + issues := gasTestRunner(` + package samples + + import "fmt" + + const password = "secret" + + func main() { + username := "admin" + fmt.Println("Doing something with: ", username, password) + }`, analyzer) + + checkTestResults(t, issues, 1, "Potential hardcoded credentials") +}