Added more rules

* Rule G406 responsible for the usage of deprecated MD4 and RIPEMD160 added.
* Rules G506, G507 responsible for tracking the usage of the already mentioned libraries added.
* Slight changes in the Makefile(`make clean` wasn't removing all expected files)
* Added license to `analyzer_test.go`
This commit is contained in:
Dimitar Banchev 2024-06-24 19:16:32 +02:00 committed by Cosmin Cojocar
parent 6382394ce8
commit 9a4a741e6b
13 changed files with 536 additions and 3 deletions

View file

@ -68,7 +68,7 @@ build-race:
go build -race -o $(BIN) ./cmd/gosec/ go build -race -o $(BIN) ./cmd/gosec/
clean: clean:
rm -rf build vendor dist coverage.txt rm -rf build vendor dist coverage.out
rm -f release image $(BIN) rm -f release image $(BIN)
release: release:

View file

@ -156,11 +156,14 @@ directory you can supply `./...` as the input argument.
- G403: Ensure minimum RSA key length of 2048 bits - G403: Ensure minimum RSA key length of 2048 bits
- G404: Insecure random number source (rand) - G404: Insecure random number source (rand)
- G405: Detect the usage of DES or RC4 - G405: Detect the usage of DES or RC4
- G406: Detect the usage of MD4 or RIPEMD160
- G501: Import blocklist: crypto/md5 - G501: Import blocklist: crypto/md5
- G502: Import blocklist: crypto/des - G502: Import blocklist: crypto/des
- G503: Import blocklist: crypto/rc4 - G503: Import blocklist: crypto/rc4
- G504: Import blocklist: net/http/cgi - G504: Import blocklist: net/http/cgi
- G505: Import blocklist: crypto/sha1 - G505: Import blocklist: crypto/sha1
- G506: Import blocklist: golang.org/x/crypto/md4
- G507: Import blocklist: golang.org/x/crypto/ripemd160
- G601: Implicit memory aliasing of items from a range statement (only for Go 1.21 or lower) - G601: Implicit memory aliasing of items from a range statement (only for Go 1.21 or lower)
- G602: Slice access out of bounds - G602: Slice access out of bounds

View file

@ -1,3 +1,17 @@
// (c) Copyright 2024 Mercedes-Benz Tech Innovation GmbH
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package gosec_test package gosec_test
import ( import (
@ -156,6 +170,22 @@ var _ = Describe("Analyzer", func() {
Expect(controlIssues).Should(HaveLen(sample.Errors)) Expect(controlIssues).Should(HaveLen(sample.Errors))
}) })
It("should find errors when nosec is not in use", func() {
sample := testutils.SampleCodeG406[0]
source := sample.Code[0]
analyzer.LoadRules(rules.Generate(false, rules.NewRuleFilter(false, "G406")).RulesInfo())
controlPackage := testutils.NewTestPackage()
defer controlPackage.Close()
controlPackage.AddFile("md4.go", source)
err := controlPackage.Build()
Expect(err).ShouldNot(HaveOccurred())
err = analyzer.Process(buildTags, controlPackage.Path)
Expect(err).ShouldNot(HaveOccurred())
controlIssues, _, _ := analyzer.Report()
Expect(controlIssues).Should(HaveLen(sample.Errors))
})
It("should report Go build errors and invalid files", func() { It("should report Go build errors and invalid files", func() {
analyzer.LoadRules(rules.Generate(false).RulesInfo()) analyzer.LoadRules(rules.Generate(false).RulesInfo())
pkg := testutils.NewTestPackage() pkg := testutils.NewTestPackage()
@ -218,6 +248,23 @@ var _ = Describe("Analyzer", func() {
Expect(nosecIssues).Should(BeEmpty()) Expect(nosecIssues).Should(BeEmpty())
}) })
It("should not report errors when a nosec line comment is present", func() {
sample := testutils.SampleCodeG406[0]
source := sample.Code[0]
analyzer.LoadRules(rules.Generate(false, rules.NewRuleFilter(false, "G406")).RulesInfo())
nosecPackage := testutils.NewTestPackage()
defer nosecPackage.Close()
nosecSource := strings.Replace(source, "h := md4.New()", "h := md4.New() //#nosec", 1)
nosecPackage.AddFile("md4.go", nosecSource)
err := nosecPackage.Build()
Expect(err).ShouldNot(HaveOccurred())
err = analyzer.Process(buildTags, nosecPackage.Path)
Expect(err).ShouldNot(HaveOccurred())
nosecIssues, _, _ := analyzer.Report()
Expect(nosecIssues).Should(BeEmpty())
})
It("should not report errors when a nosec block comment is present", func() { It("should not report errors when a nosec block comment is present", func() {
sample := testutils.SampleCodeG401[0] sample := testutils.SampleCodeG401[0]
source := sample.Code[0] source := sample.Code[0]
@ -252,6 +299,23 @@ var _ = Describe("Analyzer", func() {
Expect(nosecIssues).Should(BeEmpty()) Expect(nosecIssues).Should(BeEmpty())
}) })
It("should not report errors when a nosec block comment is present", func() {
sample := testutils.SampleCodeG406[0]
source := sample.Code[0]
analyzer.LoadRules(rules.Generate(false, rules.NewRuleFilter(false, "G406")).RulesInfo())
nosecPackage := testutils.NewTestPackage()
defer nosecPackage.Close()
nosecSource := strings.Replace(source, "h := md4.New()", "h := md4.New() /* #nosec */", 1)
nosecPackage.AddFile("md4.go", nosecSource)
err := nosecPackage.Build()
Expect(err).ShouldNot(HaveOccurred())
err = analyzer.Process(buildTags, nosecPackage.Path)
Expect(err).ShouldNot(HaveOccurred())
nosecIssues, _, _ := analyzer.Report()
Expect(nosecIssues).Should(BeEmpty())
})
It("should not report errors when an exclude comment is present for the correct rule", func() { It("should not report errors when an exclude comment is present for the correct rule", func() {
// Rule for MD5 weak crypto usage // Rule for MD5 weak crypto usage
sample := testutils.SampleCodeG401[0] sample := testutils.SampleCodeG401[0]
@ -288,6 +352,24 @@ var _ = Describe("Analyzer", func() {
Expect(nosecIssues).Should(BeEmpty()) Expect(nosecIssues).Should(BeEmpty())
}) })
It("should not report errors when an exclude comment is present for the correct rule", func() {
// Rule for MD4 deprecated weak crypto usage
sample := testutils.SampleCodeG406[0]
source := sample.Code[0]
analyzer.LoadRules(rules.Generate(false, rules.NewRuleFilter(false, "G406")).RulesInfo())
nosecPackage := testutils.NewTestPackage()
defer nosecPackage.Close()
nosecSource := strings.Replace(source, "h := md4.New()", "h := md4.New() //#nosec G406", 1)
nosecPackage.AddFile("md4.go", nosecSource)
err := nosecPackage.Build()
Expect(err).ShouldNot(HaveOccurred())
err = analyzer.Process(buildTags, nosecPackage.Path)
Expect(err).ShouldNot(HaveOccurred())
nosecIssues, _, _ := analyzer.Report()
Expect(nosecIssues).Should(BeEmpty())
})
It("should not report errors when a nosec block and line comment are present", func() { It("should not report errors when a nosec block and line comment are present", func() {
sample := testutils.SampleCodeG101[23] sample := testutils.SampleCodeG101[23]
source := sample.Code[0] source := sample.Code[0]
@ -368,6 +450,23 @@ var _ = Describe("Analyzer", func() {
Expect(nosecIssues).Should(HaveLen(sample.Errors)) Expect(nosecIssues).Should(HaveLen(sample.Errors))
}) })
It("should report errors when an exclude comment is present for a different rule", func() {
sample := testutils.SampleCodeG406[0]
source := sample.Code[0]
analyzer.LoadRules(rules.Generate(false, rules.NewRuleFilter(false, "G406")).RulesInfo())
nosecPackage := testutils.NewTestPackage()
defer nosecPackage.Close()
nosecSource := strings.Replace(source, "h := md4.New()", "h := md4.New() //#nosec G301", 1)
nosecPackage.AddFile("md4.go", nosecSource)
err := nosecPackage.Build()
Expect(err).ShouldNot(HaveOccurred())
err = analyzer.Process(buildTags, nosecPackage.Path)
Expect(err).ShouldNot(HaveOccurred())
nosecIssues, _, _ := analyzer.Report()
Expect(nosecIssues).Should(HaveLen(sample.Errors))
})
It("should not report errors when an exclude comment is present for multiple rules, including the correct rule", func() { It("should not report errors when an exclude comment is present for multiple rules, including the correct rule", func() {
sample := testutils.SampleCodeG401[0] sample := testutils.SampleCodeG401[0]
source := sample.Code[0] source := sample.Code[0]
@ -406,6 +505,25 @@ var _ = Describe("Analyzer", func() {
Expect(nosecIssues).Should(BeEmpty()) Expect(nosecIssues).Should(BeEmpty())
}) })
It("should not report errors when an exclude comment is present for multiple rules, including the correct rule", func() {
sample := testutils.SampleCodeG406[0]
source := sample.Code[0]
analyzer.LoadRules(rules.Generate(false, rules.NewRuleFilter(false, "G406")).RulesInfo())
nosecPackage := testutils.NewTestPackage()
defer nosecPackage.Close()
nosecSource := strings.Replace(source, "h := md4.New()", "h := md4.New() //#nosec G301 G406", 1)
nosecPackage.AddFile("md4.go", nosecSource)
err := nosecPackage.Build()
Expect(err).ShouldNot(HaveOccurred())
err = analyzer.Process(buildTags, nosecPackage.Path)
Expect(err).ShouldNot(HaveOccurred())
err = analyzer.Process(buildTags, nosecPackage.Path)
Expect(err).ShouldNot(HaveOccurred())
nosecIssues, _, _ := analyzer.Report()
Expect(nosecIssues).Should(BeEmpty())
})
It("should pass the build tags", func() { It("should pass the build tags", func() {
sample := testutils.SampleCodeBuildTag[0] sample := testutils.SampleCodeBuildTag[0]
source := sample.Code[0] source := sample.Code[0]
@ -479,6 +597,29 @@ var _ = Describe("Analyzer", func() {
Expect(nosecIssues).Should(HaveLen(sample.Errors)) Expect(nosecIssues).Should(HaveLen(sample.Errors))
}) })
It("should be possible to overwrite nosec comments, and report issues", func() {
// Rule for MD4 weak crypto usage
sample := testutils.SampleCodeG406[0]
source := sample.Code[0]
// overwrite nosec option
nosecIgnoreConfig := gosec.NewConfig()
nosecIgnoreConfig.SetGlobal(gosec.Nosec, "true")
customAnalyzer := gosec.NewAnalyzer(nosecIgnoreConfig, tests, false, false, 1, logger)
customAnalyzer.LoadRules(rules.Generate(false, rules.NewRuleFilter(false, "G406")).RulesInfo())
nosecPackage := testutils.NewTestPackage()
defer nosecPackage.Close()
nosecSource := strings.Replace(source, "h := md4.New()", "h := md4.New() //#nosec", 1)
nosecPackage.AddFile("md4.go", nosecSource)
err := nosecPackage.Build()
Expect(err).ShouldNot(HaveOccurred())
err = customAnalyzer.Process(buildTags, nosecPackage.Path)
Expect(err).ShouldNot(HaveOccurred())
nosecIssues, _, _ := customAnalyzer.Report()
Expect(nosecIssues).Should(HaveLen(sample.Errors))
})
It("should be possible to overwrite nosec comments, and report issues but they should not be counted", func() { It("should be possible to overwrite nosec comments, and report issues but they should not be counted", func() {
// Rule for MD5 weak crypto usage // Rule for MD5 weak crypto usage
sample := testutils.SampleCodeG401[0] sample := testutils.SampleCodeG401[0]
@ -531,6 +672,32 @@ var _ = Describe("Analyzer", func() {
Expect(metrics.NumNosec).Should(Equal(1)) Expect(metrics.NumNosec).Should(Equal(1))
}) })
It("should be possible to overwrite nosec comments, and report issues but they should not be counted", func() {
// Rule for MD4 weak crypto usage
sample := testutils.SampleCodeG406[0]
source := sample.Code[0]
// overwrite nosec option
nosecIgnoreConfig := gosec.NewConfig()
nosecIgnoreConfig.SetGlobal(gosec.Nosec, "mynosec")
nosecIgnoreConfig.SetGlobal(gosec.ShowIgnored, "true")
customAnalyzer := gosec.NewAnalyzer(nosecIgnoreConfig, tests, false, false, 1, logger)
customAnalyzer.LoadRules(rules.Generate(false, rules.NewRuleFilter(false, "G406")).RulesInfo())
nosecPackage := testutils.NewTestPackage()
defer nosecPackage.Close()
nosecSource := strings.Replace(source, "h := md4.New()", "h := md4.New() // #mynosec", 1)
nosecPackage.AddFile("md4.go", nosecSource)
err := nosecPackage.Build()
Expect(err).ShouldNot(HaveOccurred())
err = customAnalyzer.Process(buildTags, nosecPackage.Path)
Expect(err).ShouldNot(HaveOccurred())
nosecIssues, metrics, _ := customAnalyzer.Report()
Expect(nosecIssues).Should(HaveLen(sample.Errors))
Expect(metrics.NumFound).Should(Equal(0))
Expect(metrics.NumNosec).Should(Equal(1))
})
It("should not report errors when nosec tag is in front of a line", func() { It("should not report errors when nosec tag is in front of a line", func() {
sample := testutils.SampleCodeG401[0] sample := testutils.SampleCodeG401[0]
source := sample.Code[0] source := sample.Code[0]
@ -565,6 +732,23 @@ var _ = Describe("Analyzer", func() {
Expect(nosecIssues).Should(BeEmpty()) Expect(nosecIssues).Should(BeEmpty())
}) })
It("should not report errors when nosec tag is in front of a line", func() {
sample := testutils.SampleCodeG406[0]
source := sample.Code[0]
analyzer.LoadRules(rules.Generate(false, rules.NewRuleFilter(false, "G406")).RulesInfo())
nosecPackage := testutils.NewTestPackage()
defer nosecPackage.Close()
nosecSource := strings.Replace(source, "h := md4.New()", "//Some description\n//#nosec G406\nh := md4.New()", 1)
nosecPackage.AddFile("md4.go", nosecSource)
err := nosecPackage.Build()
Expect(err).ShouldNot(HaveOccurred())
err = analyzer.Process(buildTags, nosecPackage.Path)
Expect(err).ShouldNot(HaveOccurred())
nosecIssues, _, _ := analyzer.Report()
Expect(nosecIssues).Should(BeEmpty())
})
It("should report errors when nosec tag is not in front of a line", func() { It("should report errors when nosec tag is not in front of a line", func() {
sample := testutils.SampleCodeG401[0] sample := testutils.SampleCodeG401[0]
source := sample.Code[0] source := sample.Code[0]
@ -599,6 +783,23 @@ var _ = Describe("Analyzer", func() {
Expect(nosecIssues).Should(HaveLen(sample.Errors)) Expect(nosecIssues).Should(HaveLen(sample.Errors))
}) })
It("should report errors when nosec tag is not in front of a line", func() {
sample := testutils.SampleCodeG406[0]
source := sample.Code[0]
analyzer.LoadRules(rules.Generate(false, rules.NewRuleFilter(false, "G406")).RulesInfo())
nosecPackage := testutils.NewTestPackage()
defer nosecPackage.Close()
nosecSource := strings.Replace(source, "h := md4.New()", "//Some description\n//Another description #nosec G406\nh := md4.New()", 1)
nosecPackage.AddFile("md4.go", nosecSource)
err := nosecPackage.Build()
Expect(err).ShouldNot(HaveOccurred())
err = analyzer.Process(buildTags, nosecPackage.Path)
Expect(err).ShouldNot(HaveOccurred())
nosecIssues, _, _ := analyzer.Report()
Expect(nosecIssues).Should(HaveLen(sample.Errors))
})
It("should not report errors when rules are in front of nosec tag even rules are wrong", func() { It("should not report errors when rules are in front of nosec tag even rules are wrong", func() {
sample := testutils.SampleCodeG401[0] sample := testutils.SampleCodeG401[0]
source := sample.Code[0] source := sample.Code[0]
@ -633,6 +834,23 @@ var _ = Describe("Analyzer", func() {
Expect(nosecIssues).Should(BeEmpty()) Expect(nosecIssues).Should(BeEmpty())
}) })
It("should not report errors when rules are in front of nosec tag even rules are wrong", func() {
sample := testutils.SampleCodeG406[0]
source := sample.Code[0]
analyzer.LoadRules(rules.Generate(false, rules.NewRuleFilter(false, "G406")).RulesInfo())
nosecPackage := testutils.NewTestPackage()
defer nosecPackage.Close()
nosecSource := strings.Replace(source, "h := md4.New()", "//G301\n//#nosec\nh := md4.New()", 1)
nosecPackage.AddFile("md4.go", nosecSource)
err := nosecPackage.Build()
Expect(err).ShouldNot(HaveOccurred())
err = analyzer.Process(buildTags, nosecPackage.Path)
Expect(err).ShouldNot(HaveOccurred())
nosecIssues, _, _ := analyzer.Report()
Expect(nosecIssues).Should(BeEmpty())
})
It("should report errors when there are nosec tags after a #nosec WrongRuleList annotation", func() { It("should report errors when there are nosec tags after a #nosec WrongRuleList annotation", func() {
sample := testutils.SampleCodeG401[0] sample := testutils.SampleCodeG401[0]
source := sample.Code[0] source := sample.Code[0]
@ -667,6 +885,23 @@ var _ = Describe("Analyzer", func() {
Expect(nosecIssues).Should(HaveLen(sample.Errors)) Expect(nosecIssues).Should(HaveLen(sample.Errors))
}) })
It("should report errors when there are nosec tags after a #nosec WrongRuleList annotation", func() {
sample := testutils.SampleCodeG406[0]
source := sample.Code[0]
analyzer.LoadRules(rules.Generate(false, rules.NewRuleFilter(false, "G406")).RulesInfo())
nosecPackage := testutils.NewTestPackage()
defer nosecPackage.Close()
nosecSource := strings.Replace(source, "h := md4.New()", "//#nosec\n//G301\n//#nosec\nh := md4.New()", 1)
nosecPackage.AddFile("md4.go", nosecSource)
err := nosecPackage.Build()
Expect(err).ShouldNot(HaveOccurred())
err = analyzer.Process(buildTags, nosecPackage.Path)
Expect(err).ShouldNot(HaveOccurred())
nosecIssues, _, _ := analyzer.Report()
Expect(nosecIssues).Should(HaveLen(sample.Errors))
})
It("should be possible to use an alternative nosec tag", func() { It("should be possible to use an alternative nosec tag", func() {
// Rule for MD5 weak crypto usage // Rule for MD5 weak crypto usage
sample := testutils.SampleCodeG401[0] sample := testutils.SampleCodeG401[0]
@ -713,6 +948,29 @@ var _ = Describe("Analyzer", func() {
Expect(nosecIssues).Should(BeEmpty()) Expect(nosecIssues).Should(BeEmpty())
}) })
It("should be possible to use an alternative nosec tag", func() {
// Rule for MD4 deprecated weak crypto usage
sample := testutils.SampleCodeG406[0]
source := sample.Code[0]
// overwrite nosec option
nosecIgnoreConfig := gosec.NewConfig()
nosecIgnoreConfig.SetGlobal(gosec.NoSecAlternative, "falsePositive")
customAnalyzer := gosec.NewAnalyzer(nosecIgnoreConfig, tests, false, false, 1, logger)
customAnalyzer.LoadRules(rules.Generate(false, rules.NewRuleFilter(false, "G406")).RulesInfo())
nosecPackage := testutils.NewTestPackage()
defer nosecPackage.Close()
nosecSource := strings.Replace(source, "h := md4.New()", "h := md4.New() // #falsePositive", 1)
nosecPackage.AddFile("md4.go", nosecSource)
err := nosecPackage.Build()
Expect(err).ShouldNot(HaveOccurred())
err = customAnalyzer.Process(buildTags, nosecPackage.Path)
Expect(err).ShouldNot(HaveOccurred())
nosecIssues, _, _ := customAnalyzer.Report()
Expect(nosecIssues).Should(BeEmpty())
})
It("should ignore vulnerabilities when the default tag is found", func() { It("should ignore vulnerabilities when the default tag is found", func() {
// Rule for MD5 weak crypto usage // Rule for MD5 weak crypto usage
sample := testutils.SampleCodeG401[0] sample := testutils.SampleCodeG401[0]
@ -759,6 +1017,29 @@ var _ = Describe("Analyzer", func() {
Expect(nosecIssues).Should(BeEmpty()) Expect(nosecIssues).Should(BeEmpty())
}) })
It("should ignore vulnerabilities when the default tag is found", func() {
// Rule for MD4 deprecated weak crypto usage
sample := testutils.SampleCodeG406[0]
source := sample.Code[0]
// overwrite nosec option
nosecIgnoreConfig := gosec.NewConfig()
nosecIgnoreConfig.SetGlobal(gosec.NoSecAlternative, "falsePositive")
customAnalyzer := gosec.NewAnalyzer(nosecIgnoreConfig, tests, false, false, 1, logger)
customAnalyzer.LoadRules(rules.Generate(false, rules.NewRuleFilter(false, "G406")).RulesInfo())
nosecPackage := testutils.NewTestPackage()
defer nosecPackage.Close()
nosecSource := strings.Replace(source, "h := md4.New()", "h := md4.New() //#nosec", 1)
nosecPackage.AddFile("md4.go", nosecSource)
err := nosecPackage.Build()
Expect(err).ShouldNot(HaveOccurred())
err = customAnalyzer.Process(buildTags, nosecPackage.Path)
Expect(err).ShouldNot(HaveOccurred())
nosecIssues, _, _ := customAnalyzer.Report()
Expect(nosecIssues).Should(BeEmpty())
})
It("should be able to analyze Go test package", func() { It("should be able to analyze Go test package", func() {
customAnalyzer := gosec.NewAnalyzer(nil, true, false, false, 1, logger) customAnalyzer := gosec.NewAnalyzer(nil, true, false, false, 1, logger)
customAnalyzer.LoadRules(rules.Generate(false).RulesInfo()) customAnalyzer.LoadRules(rules.Generate(false).RulesInfo())
@ -1100,6 +1381,26 @@ var _ = Describe("Analyzer", func() {
Expect(issues[0].Suppressions[0].Justification).To(Equal("Justification")) Expect(issues[0].Suppressions[0].Justification).To(Equal("Justification"))
}) })
It("should not report an error if the violation is suppressed", func() {
sample := testutils.SampleCodeG406[0]
source := sample.Code[0]
analyzer.LoadRules(rules.Generate(false, rules.NewRuleFilter(false, "G406")).RulesInfo())
nosecPackage := testutils.NewTestPackage()
defer nosecPackage.Close()
nosecSource := strings.Replace(source, "h := md4.New()", "h := md4.New() //#nosec G406 -- Justification", 1)
nosecPackage.AddFile("md4.go", nosecSource)
err := nosecPackage.Build()
Expect(err).ShouldNot(HaveOccurred())
err = analyzer.Process(buildTags, nosecPackage.Path)
Expect(err).ShouldNot(HaveOccurred())
issues, _, _ := analyzer.Report()
Expect(issues).To(HaveLen(sample.Errors))
Expect(issues[0].Suppressions).To(HaveLen(1))
Expect(issues[0].Suppressions[0].Kind).To(Equal("inSource"))
Expect(issues[0].Suppressions[0].Justification).To(Equal("Justification"))
})
It("should not report an error if the violation is suppressed without certain rules", func() { It("should not report an error if the violation is suppressed without certain rules", func() {
sample := testutils.SampleCodeG401[0] sample := testutils.SampleCodeG401[0]
source := sample.Code[0] source := sample.Code[0]
@ -1140,6 +1441,26 @@ var _ = Describe("Analyzer", func() {
Expect(issues[0].Suppressions[0].Justification).To(Equal("")) Expect(issues[0].Suppressions[0].Justification).To(Equal(""))
}) })
It("should not report an error if the violation is suppressed without certain rules", func() {
sample := testutils.SampleCodeG406[0]
source := sample.Code[0]
analyzer.LoadRules(rules.Generate(false, rules.NewRuleFilter(false, "G406")).RulesInfo())
nosecPackage := testutils.NewTestPackage()
defer nosecPackage.Close()
nosecSource := strings.Replace(source, "h := md4.New()", "h := md4.New() //#nosec", 1)
nosecPackage.AddFile("md4.go", nosecSource)
err := nosecPackage.Build()
Expect(err).ShouldNot(HaveOccurred())
err = analyzer.Process(buildTags, nosecPackage.Path)
Expect(err).ShouldNot(HaveOccurred())
issues, _, _ := analyzer.Report()
Expect(issues).To(HaveLen(sample.Errors))
Expect(issues[0].Suppressions).To(HaveLen(1))
Expect(issues[0].Suppressions[0].Kind).To(Equal("inSource"))
Expect(issues[0].Suppressions[0].Justification).To(Equal(""))
})
It("should not report an error if the rule is not included", func() { It("should not report an error if the rule is not included", func() {
sample := testutils.SampleCodeG101[0] sample := testutils.SampleCodeG101[0]
source := sample.Code[0] source := sample.Code[0]

View file

@ -119,6 +119,31 @@ var _ = Describe("Call List", func() {
Expect(matched).Should(Equal(1)) Expect(matched).Should(Equal(1))
}) })
It("should match a package call expression", func() {
// Create file to be scanned
pkg := testutils.NewTestPackage()
defer pkg.Close()
pkg.AddFile("md4.go", testutils.SampleCodeG406[0].Code[0])
ctx := pkg.CreateContext("md4.go")
// Search for md4.New()
calls.Add("golang.org/x/crypto/md4", "New")
// Stub out visitor and count number of matched call expr
matched := 0
v := testutils.NewMockVisitor()
v.Context = ctx
v.Callback = func(n ast.Node, ctx *gosec.Context) bool {
if _, ok := n.(*ast.CallExpr); ok && calls.ContainsPkgCallExpr(n, ctx, false) != nil {
matched++
}
return true
}
ast.Walk(v, ctx.Root)
Expect(matched).Should(Equal(1))
})
It("should match a call expression", func() { It("should match a call expression", func() {
// Create file to be scanned // Create file to be scanned
pkg := testutils.NewTestPackage() pkg := testutils.NewTestPackage()

View file

@ -83,11 +83,14 @@ var ruleToCWE = map[string]string{
"G403": "310", "G403": "310",
"G404": "338", "G404": "338",
"G405": "327", "G405": "327",
"G406": "328",
"G501": "327", "G501": "327",
"G502": "327", "G502": "327",
"G503": "327", "G503": "327",
"G504": "327", "G504": "327",
"G505": "327", "G505": "327",
"G506": "327",
"G507": "327",
"G601": "118", "G601": "118",
"G602": "118", "G602": "118",
} }

View file

@ -281,8 +281,8 @@ var _ = Describe("Formatter", func() {
"G101", "G102", "G103", "G104", "G106", "G107", "G109", "G101", "G102", "G103", "G104", "G106", "G107", "G109",
"G110", "G111", "G112", "G113", "G201", "G202", "G203", "G110", "G111", "G112", "G113", "G201", "G202", "G203",
"G204", "G301", "G302", "G303", "G304", "G305", "G401", "G204", "G301", "G302", "G303", "G304", "G305", "G401",
"G402", "G403", "G404", "G405", "G501", "G502", "G503", "G402", "G403", "G404", "G405", "G406", "G501", "G502",
"G504", "G505", "G601", "G503", "G504", "G505", "G506", "G507", "G601",
} }
It("csv formatted report should contain the CWE mapping", func() { It("csv formatted report should contain the CWE mapping", func() {

View file

@ -93,3 +93,17 @@ func NewBlocklistedImportSHA1(id string, conf gosec.Config) (gosec.Rule, []ast.N
"crypto/sha1": "Blocklisted import crypto/sha1: weak cryptographic primitive", "crypto/sha1": "Blocklisted import crypto/sha1: weak cryptographic primitive",
}) })
} }
// NewBlocklistedImportMD4 fails if MD4 is imported
func NewBlocklistedImportMD4(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
return NewBlocklistedImports(id, conf, map[string]string{
"golang.org/x/crypto/md4": "Blocklisted import golang.org/x/crypto/md4: deprecated and weak cryptographic primitive",
})
}
// NewBlocklistedImportRIPEMD160 fails if RIPEMD160 is imported
func NewBlocklistedImportRIPEMD160(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
return NewBlocklistedImports(id, conf, map[string]string{
"golang.org/x/crypto/ripemd160": "Blocklisted import golang.org/x/crypto/ripemd160: deprecated and weak cryptographic primitive",
})
}

View file

@ -99,6 +99,7 @@ func Generate(trackSuppressions bool, filters ...RuleFilter) RuleList {
{"G403", "Ensure minimum RSA key length of 2048 bits", NewWeakKeyStrength}, {"G403", "Ensure minimum RSA key length of 2048 bits", NewWeakKeyStrength},
{"G404", "Insecure random number source (rand)", NewWeakRandCheck}, {"G404", "Insecure random number source (rand)", NewWeakRandCheck},
{"G405", "Detect the usage of DES or RC4", NewUsesWeakCryptographyEncryption}, {"G405", "Detect the usage of DES or RC4", NewUsesWeakCryptographyEncryption},
{"G406", "Detect the usage of deprecated MD4 or RIPEMD160", NewUsesWeakDeprecatedCryptographyHash},
// blocklist // blocklist
{"G501", "Import blocklist: crypto/md5", NewBlocklistedImportMD5}, {"G501", "Import blocklist: crypto/md5", NewBlocklistedImportMD5},
@ -106,6 +107,8 @@ func Generate(trackSuppressions bool, filters ...RuleFilter) RuleList {
{"G503", "Import blocklist: crypto/rc4", NewBlocklistedImportRC4}, {"G503", "Import blocklist: crypto/rc4", NewBlocklistedImportRC4},
{"G504", "Import blocklist: net/http/cgi", NewBlocklistedImportCGI}, {"G504", "Import blocklist: net/http/cgi", NewBlocklistedImportCGI},
{"G505", "Import blocklist: crypto/sha1", NewBlocklistedImportSHA1}, {"G505", "Import blocklist: crypto/sha1", NewBlocklistedImportSHA1},
{"G506", "Import blocklist: golang.org/x/crypto/md4", NewBlocklistedImportMD4},
{"G507", "Import blocklist: golang.org/x/crypto/ripemd160", NewBlocklistedImportRIPEMD160},
// memory safety // memory safety
{"G601", "Implicit memory aliasing in RangeStmt", NewImplicitAliasing}, {"G601", "Implicit memory aliasing in RangeStmt", NewImplicitAliasing},

View file

@ -183,6 +183,14 @@ var _ = Describe("gosec rules", func() {
runner("G405", testutils.SampleCodeG405b) runner("G405", testutils.SampleCodeG405b)
}) })
It("should detect weak crypto algorithms", func() {
runner("G406", testutils.SampleCodeG406)
})
It("should detect weak crypto algorithms", func() {
runner("G406", testutils.SampleCodeG406b)
})
It("should detect blocklisted imports - MD5", func() { It("should detect blocklisted imports - MD5", func() {
runner("G501", testutils.SampleCodeG501) runner("G501", testutils.SampleCodeG501)
}) })
@ -203,6 +211,14 @@ var _ = Describe("gosec rules", func() {
runner("G505", testutils.SampleCodeG505) runner("G505", testutils.SampleCodeG505)
}) })
It("should detect blocklisted imports - MD4", func() {
runner("G506", testutils.SampleCodeG506)
})
It("should detect blocklisted imports - RIPEMD160", func() {
runner("G507", testutils.SampleCodeG507)
})
It("should detect implicit aliasing in ForRange", func() { It("should detect implicit aliasing in ForRange", func() {
major, minor, _ := gosec.GoVersion() major, minor, _ := gosec.GoVersion()
if major <= 1 && minor < 22 { if major <= 1 && minor < 22 {

View file

@ -0,0 +1,57 @@
// (c) Copyright 2024 Mercedes-Benz Tech Innovation GmbH
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package rules
import (
"go/ast"
"github.com/securego/gosec/v2"
"github.com/securego/gosec/v2/issue"
)
type usesWeakDeprecatedCryptographyHash struct {
issue.MetaData
blocklist map[string][]string
}
func (r *usesWeakDeprecatedCryptographyHash) ID() string {
return r.MetaData.ID
}
func (r *usesWeakDeprecatedCryptographyHash) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
for pkg, funcs := range r.blocklist {
if _, matched := gosec.MatchCallByPackage(n, c, pkg, funcs...); matched {
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
}
}
return nil, nil
}
// NewUsesWeakCryptographyHash detects uses of md4.New, ripemd160.New
func NewUsesWeakDeprecatedCryptographyHash(id string, _ gosec.Config) (gosec.Rule, []ast.Node) {
calls := make(map[string][]string)
calls["golang.org/x/crypto/md4"] = []string{"New"}
calls["golang.org/x/crypto/ripemd160"] = []string{"New"}
rule := &usesWeakDeprecatedCryptographyHash{
blocklist: calls,
MetaData: issue.MetaData{
ID: id,
Severity: issue.Medium,
Confidence: issue.High,
What: "Use of deprecated weak cryptographic primitive",
},
}
return rule, []ast.Node{(*ast.CallExpr)(nil)}
}

45
testutils/g406_samples.go Normal file
View file

@ -0,0 +1,45 @@
package testutils
import "github.com/securego/gosec/v2"
var (
// SampleCodeG406 - Use of deprecated weak crypto hash MD4
SampleCodeG406 = []CodeSample{
{[]string{`
package main
import (
"encoding/hex"
"fmt"
"golang.org/x/crypto/md4"
)
func main() {
h := md4.New()
h.Write([]byte("test"))
fmt.Println(hex.EncodeToString(h.Sum(nil)))
}
`}, 1, gosec.NewConfig()},
}
// SampleCodeG406b - Use of deprecated weak crypto hash RIPEMD160
SampleCodeG406b = []CodeSample{
{[]string{`
package main
import (
"encoding/hex"
"fmt"
"golang.org/x/crypto/ripemd160"
)
func main() {
h := ripemd160.New()
h.Write([]byte("test"))
fmt.Println(hex.EncodeToString(h.Sum(nil)))
}
`}, 1, gosec.NewConfig()},
}
)

23
testutils/g506_samples.go Normal file
View file

@ -0,0 +1,23 @@
package testutils
import "github.com/securego/gosec/v2"
// SampleCodeG506 - Blocklisted import MD4
var SampleCodeG506 = []CodeSample{
{[]string{`
package main
import (
"encoding/hex"
"fmt"
"golang.org/x/crypto/md4"
)
func main() {
h := md4.New()
h.Write([]byte("test"))
fmt.Println(hex.EncodeToString(h.Sum(nil)))
}
`}, 1, gosec.NewConfig()},
}

23
testutils/g507_samples.go Normal file
View file

@ -0,0 +1,23 @@
package testutils
import "github.com/securego/gosec/v2"
// SampleCodeG507 - Blocklisted import RIPEMD160
var SampleCodeG507 = []CodeSample{
{[]string{`
package main
import (
"encoding/hex"
"fmt"
"golang.org/x/crypto/ripemd160"
)
func main() {
h := ripemd160.New()
h.Write([]byte("test"))
fmt.Println(hex.EncodeToString(h.Sum(nil)))
}
`}, 1, gosec.NewConfig()},
}