mirror of
https://github.com/securego/gosec.git
synced 2024-12-25 03:55:54 +00:00
Extract the issue in its own package
This commit is contained in:
parent
31e63276f1
commit
de2c6a36fa
48 changed files with 439 additions and 378 deletions
5
Makefile
5
Makefile
|
@ -87,4 +87,7 @@ image-push: image
|
||||||
docker push $(IMAGE_REPO)/$(BIN):$(GIT_TAG)
|
docker push $(IMAGE_REPO)/$(BIN):$(GIT_TAG)
|
||||||
docker push $(IMAGE_REPO)/$(BIN):latest
|
docker push $(IMAGE_REPO)/$(BIN):latest
|
||||||
|
|
||||||
.PHONY: test build clean release image image-push
|
tlsconfig:
|
||||||
|
go generate ./...
|
||||||
|
|
||||||
|
.PHONY: test build clean release image image-push tlsconfig
|
||||||
|
|
69
analyzer.go
69
analyzer.go
|
@ -32,6 +32,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/securego/gosec/v2/analyzers"
|
"github.com/securego/gosec/v2/analyzers"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
"golang.org/x/tools/go/analysis"
|
"golang.org/x/tools/go/analysis"
|
||||||
"golang.org/x/tools/go/analysis/passes/buildssa"
|
"golang.org/x/tools/go/analysis/passes/buildssa"
|
||||||
"golang.org/x/tools/go/packages"
|
"golang.org/x/tools/go/packages"
|
||||||
|
@ -68,10 +69,21 @@ type Context struct {
|
||||||
Root *ast.File
|
Root *ast.File
|
||||||
Imports *ImportTracker
|
Imports *ImportTracker
|
||||||
Config Config
|
Config Config
|
||||||
Ignores []map[string][]SuppressionInfo
|
Ignores []map[string][]issue.SuppressionInfo
|
||||||
PassedValues map[string]interface{}
|
PassedValues map[string]interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getFileAtNodePos returns the file at the node position in the file set available in the context.
|
||||||
|
func (ctx *Context) GetFileAtNodePos(node ast.Node) *token.File {
|
||||||
|
return ctx.FileSet.File(node.Pos())
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewIssue creates a new issue
|
||||||
|
func (ctx *Context) NewIssue(node ast.Node, ruleID, desc string,
|
||||||
|
severity, confidence issue.Score) *issue.Issue {
|
||||||
|
return issue.New(ctx.GetFileAtNodePos(node), node, ruleID, desc, severity, confidence)
|
||||||
|
}
|
||||||
|
|
||||||
// Metrics used when reporting information about a scanning run.
|
// Metrics used when reporting information about a scanning run.
|
||||||
type Metrics struct {
|
type Metrics struct {
|
||||||
NumFiles int `json:"files"`
|
NumFiles int `json:"files"`
|
||||||
|
@ -88,7 +100,7 @@ type Analyzer struct {
|
||||||
context *Context
|
context *Context
|
||||||
config Config
|
config Config
|
||||||
logger *log.Logger
|
logger *log.Logger
|
||||||
issues []*Issue
|
issues []*issue.Issue
|
||||||
stats *Metrics
|
stats *Metrics
|
||||||
errors map[string][]Error // keys are file paths; values are the golang errors in those files
|
errors map[string][]Error // keys are file paths; values are the golang errors in those files
|
||||||
tests bool
|
tests bool
|
||||||
|
@ -99,13 +111,6 @@ type Analyzer struct {
|
||||||
analyzerList []*analysis.Analyzer
|
analyzerList []*analysis.Analyzer
|
||||||
}
|
}
|
||||||
|
|
||||||
// SuppressionInfo object is to record the kind and the justification that used
|
|
||||||
// to suppress violations.
|
|
||||||
type SuppressionInfo struct {
|
|
||||||
Kind string `json:"kind"`
|
|
||||||
Justification string `json:"justification"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewAnalyzer builds a new analyzer.
|
// NewAnalyzer builds a new analyzer.
|
||||||
func NewAnalyzer(conf Config, tests bool, excludeGenerated bool, trackSuppressions bool, concurrency int, logger *log.Logger) *Analyzer {
|
func NewAnalyzer(conf Config, tests bool, excludeGenerated bool, trackSuppressions bool, concurrency int, logger *log.Logger) *Analyzer {
|
||||||
ignoreNoSec := false
|
ignoreNoSec := false
|
||||||
|
@ -126,7 +131,7 @@ func NewAnalyzer(conf Config, tests bool, excludeGenerated bool, trackSuppressio
|
||||||
context: &Context{},
|
context: &Context{},
|
||||||
config: conf,
|
config: conf,
|
||||||
logger: logger,
|
logger: logger,
|
||||||
issues: make([]*Issue, 0, 16),
|
issues: make([]*issue.Issue, 0, 16),
|
||||||
stats: &Metrics{},
|
stats: &Metrics{},
|
||||||
errors: make(map[string][]Error),
|
errors: make(map[string][]Error),
|
||||||
tests: tests,
|
tests: tests,
|
||||||
|
@ -371,8 +376,8 @@ func (gosec *Analyzer) CheckAnalyzers(pkg *packages.Package) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if result != nil {
|
if result != nil {
|
||||||
if issue, ok := result.(*analyzers.Issue); ok {
|
if aissue, ok := result.(*analyzers.Issue); ok {
|
||||||
gosec.updateIssues(toGosecIssue(issue), false, []SuppressionInfo{})
|
gosec.updateIssues(toGosecIssue(aissue), false, []issue.SuppressionInfo{})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -439,7 +444,7 @@ func (gosec *Analyzer) AppendError(file string, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore a node (and sub-tree) if it is tagged with a nosec tag comment
|
// ignore a node (and sub-tree) if it is tagged with a nosec tag comment
|
||||||
func (gosec *Analyzer) ignore(n ast.Node) map[string]SuppressionInfo {
|
func (gosec *Analyzer) ignore(n ast.Node) map[string]issue.SuppressionInfo {
|
||||||
if groups, ok := gosec.context.Comments[n]; ok && !gosec.ignoreNosec {
|
if groups, ok := gosec.context.Comments[n]; ok && !gosec.ignoreNosec {
|
||||||
|
|
||||||
// Checks if an alternative for #nosec is set and, if not, uses the default.
|
// Checks if an alternative for #nosec is set and, if not, uses the default.
|
||||||
|
@ -476,13 +481,13 @@ func (gosec *Analyzer) ignore(n ast.Node) map[string]SuppressionInfo {
|
||||||
re := regexp.MustCompile(`(G\d{3})`)
|
re := regexp.MustCompile(`(G\d{3})`)
|
||||||
matches := re.FindAllStringSubmatch(directive, -1)
|
matches := re.FindAllStringSubmatch(directive, -1)
|
||||||
|
|
||||||
suppression := SuppressionInfo{
|
suppression := issue.SuppressionInfo{
|
||||||
Kind: "inSource",
|
Kind: "inSource",
|
||||||
Justification: justification,
|
Justification: justification,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the rule IDs to ignore.
|
// Find the rule IDs to ignore.
|
||||||
ignores := make(map[string]SuppressionInfo)
|
ignores := make(map[string]issue.SuppressionInfo)
|
||||||
for _, v := range matches {
|
for _, v := range matches {
|
||||||
ignores[v[1]] = suppression
|
ignores[v[1]] = suppression
|
||||||
}
|
}
|
||||||
|
@ -525,7 +530,7 @@ func (gosec *Analyzer) Visit(n ast.Node) ast.Visitor {
|
||||||
return gosec
|
return gosec
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gosec *Analyzer) updateIgnoredRules(n ast.Node) (map[string][]SuppressionInfo, bool) {
|
func (gosec *Analyzer) updateIgnoredRules(n ast.Node) (map[string][]issue.SuppressionInfo, bool) {
|
||||||
if n == nil {
|
if n == nil {
|
||||||
if len(gosec.context.Ignores) > 0 {
|
if len(gosec.context.Ignores) > 0 {
|
||||||
gosec.context.Ignores = gosec.context.Ignores[1:]
|
gosec.context.Ignores = gosec.context.Ignores[1:]
|
||||||
|
@ -536,7 +541,7 @@ func (gosec *Analyzer) updateIgnoredRules(n ast.Node) (map[string][]SuppressionI
|
||||||
ignoredRules := gosec.ignore(n)
|
ignoredRules := gosec.ignore(n)
|
||||||
|
|
||||||
// Now create the union of exclusions.
|
// Now create the union of exclusions.
|
||||||
ignores := map[string][]SuppressionInfo{}
|
ignores := map[string][]issue.SuppressionInfo{}
|
||||||
if len(gosec.context.Ignores) > 0 {
|
if len(gosec.context.Ignores) > 0 {
|
||||||
for k, v := range gosec.context.Ignores[0] {
|
for k, v := range gosec.context.Ignores[0] {
|
||||||
ignores[k] = v
|
ignores[k] = v
|
||||||
|
@ -548,12 +553,12 @@ func (gosec *Analyzer) updateIgnoredRules(n ast.Node) (map[string][]SuppressionI
|
||||||
}
|
}
|
||||||
|
|
||||||
// Push the new set onto the stack.
|
// Push the new set onto the stack.
|
||||||
gosec.context.Ignores = append([]map[string][]SuppressionInfo{ignores}, gosec.context.Ignores...)
|
gosec.context.Ignores = append([]map[string][]issue.SuppressionInfo{ignores}, gosec.context.Ignores...)
|
||||||
|
|
||||||
return ignores, true
|
return ignores, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gosec *Analyzer) updateSuppressions(id string, ignores map[string][]SuppressionInfo) ([]SuppressionInfo, bool) {
|
func (gosec *Analyzer) updateSuppressions(id string, ignores map[string][]issue.SuppressionInfo) ([]issue.SuppressionInfo, bool) {
|
||||||
// Check if all rules are ignored.
|
// Check if all rules are ignored.
|
||||||
generalSuppressions, generalIgnored := ignores[aliasOfAllRules]
|
generalSuppressions, generalIgnored := ignores[aliasOfAllRules]
|
||||||
// Check if the specific rule is ignored
|
// Check if the specific rule is ignored
|
||||||
|
@ -565,7 +570,7 @@ func (gosec *Analyzer) updateSuppressions(id string, ignores map[string][]Suppre
|
||||||
// Track external suppressions.
|
// Track external suppressions.
|
||||||
if gosec.ruleset.IsRuleSuppressed(id) {
|
if gosec.ruleset.IsRuleSuppressed(id) {
|
||||||
ignored = true
|
ignored = true
|
||||||
suppressions = append(suppressions, SuppressionInfo{
|
suppressions = append(suppressions, issue.SuppressionInfo{
|
||||||
Kind: "external",
|
Kind: "external",
|
||||||
Justification: externalSuppressionJustification,
|
Justification: externalSuppressionJustification,
|
||||||
})
|
})
|
||||||
|
@ -573,7 +578,7 @@ func (gosec *Analyzer) updateSuppressions(id string, ignores map[string][]Suppre
|
||||||
return suppressions, ignored
|
return suppressions, ignored
|
||||||
}
|
}
|
||||||
|
|
||||||
func (gosec *Analyzer) updateIssues(issue *Issue, ignored bool, suppressions []SuppressionInfo) {
|
func (gosec *Analyzer) updateIssues(issue *issue.Issue, ignored bool, suppressions []issue.SuppressionInfo) {
|
||||||
if issue != nil {
|
if issue != nil {
|
||||||
if gosec.showIgnored {
|
if gosec.showIgnored {
|
||||||
issue.NoSec = ignored
|
issue.NoSec = ignored
|
||||||
|
@ -590,27 +595,27 @@ func (gosec *Analyzer) updateIssues(issue *Issue, ignored bool, suppressions []S
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func toGosecIssue(issue *analyzers.Issue) *Issue {
|
func toGosecIssue(aissue *analyzers.Issue) *issue.Issue {
|
||||||
return &Issue{
|
return &issue.Issue{
|
||||||
File: issue.File,
|
File: aissue.File,
|
||||||
Line: issue.Line,
|
Line: aissue.Line,
|
||||||
Col: issue.Col,
|
Col: aissue.Col,
|
||||||
RuleID: issue.AnalyzerID,
|
RuleID: aissue.AnalyzerID,
|
||||||
What: issue.What,
|
What: aissue.What,
|
||||||
Confidence: Score(issue.Confidence),
|
Confidence: issue.Score(aissue.Confidence),
|
||||||
Severity: Score(issue.Severity),
|
Severity: issue.Score(aissue.Severity),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Report returns the current issues discovered and the metrics about the scan
|
// Report returns the current issues discovered and the metrics about the scan
|
||||||
func (gosec *Analyzer) Report() ([]*Issue, *Metrics, map[string][]Error) {
|
func (gosec *Analyzer) Report() ([]*issue.Issue, *Metrics, map[string][]Error) {
|
||||||
return gosec.issues, gosec.stats, gosec.errors
|
return gosec.issues, gosec.stats, gosec.errors
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset clears state such as context, issues and metrics from the configured analyzer
|
// Reset clears state such as context, issues and metrics from the configured analyzer
|
||||||
func (gosec *Analyzer) Reset() {
|
func (gosec *Analyzer) Reset() {
|
||||||
gosec.context = &Context{}
|
gosec.context = &Context{}
|
||||||
gosec.issues = make([]*Issue, 0, 16)
|
gosec.issues = make([]*issue.Issue, 0, 16)
|
||||||
gosec.stats = &Metrics{}
|
gosec.stats = &Metrics{}
|
||||||
gosec.ruleset = NewRuleSet()
|
gosec.ruleset = NewRuleSet()
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ import (
|
||||||
|
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
"github.com/securego/gosec/v2/cmd/vflag"
|
"github.com/securego/gosec/v2/cmd/vflag"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
"github.com/securego/gosec/v2/report"
|
"github.com/securego/gosec/v2/report"
|
||||||
"github.com/securego/gosec/v2/rules"
|
"github.com/securego/gosec/v2/rules"
|
||||||
)
|
)
|
||||||
|
@ -265,22 +266,22 @@ func saveReport(filename, format string, rootPaths []string, reportInfo *gosec.R
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertToScore(value string) (gosec.Score, error) {
|
func convertToScore(value string) (issue.Score, error) {
|
||||||
value = strings.ToLower(value)
|
value = strings.ToLower(value)
|
||||||
switch value {
|
switch value {
|
||||||
case "low":
|
case "low":
|
||||||
return gosec.Low, nil
|
return issue.Low, nil
|
||||||
case "medium":
|
case "medium":
|
||||||
return gosec.Medium, nil
|
return issue.Medium, nil
|
||||||
case "high":
|
case "high":
|
||||||
return gosec.High, nil
|
return issue.High, nil
|
||||||
default:
|
default:
|
||||||
return gosec.Low, fmt.Errorf("provided value '%s' not valid. Valid options: low, medium, high", value)
|
return issue.Low, fmt.Errorf("provided value '%s' not valid. Valid options: low, medium, high", value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterIssues(issues []*gosec.Issue, severity gosec.Score, confidence gosec.Score) ([]*gosec.Issue, int) {
|
func filterIssues(issues []*issue.Issue, severity issue.Score, confidence issue.Score) ([]*issue.Issue, int) {
|
||||||
result := make([]*gosec.Issue, 0)
|
result := make([]*issue.Issue, 0)
|
||||||
trueIssues := 0
|
trueIssues := 0
|
||||||
for _, issue := range issues {
|
for _, issue := range issues {
|
||||||
if issue.Severity >= severity && issue.Confidence >= confidence {
|
if issue.Severity >= severity && issue.Confidence >= confidence {
|
||||||
|
@ -293,7 +294,7 @@ func filterIssues(issues []*gosec.Issue, severity gosec.Score, confidence gosec.
|
||||||
return result, trueIssues
|
return result, trueIssues
|
||||||
}
|
}
|
||||||
|
|
||||||
func exit(issues []*gosec.Issue, errors map[string][]gosec.Error, noFail bool) {
|
func exit(issues []*issue.Issue, errors map[string][]gosec.Error, noFail bool) {
|
||||||
nsi := 0
|
nsi := 0
|
||||||
for _, issue := range issues {
|
for _, issue := range issues {
|
||||||
if len(issue.Suppressions) == 0 {
|
if len(issue.Suppressions) == 0 {
|
||||||
|
|
|
@ -5,7 +5,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2/issue"
|
||||||
)
|
)
|
||||||
|
|
||||||
// handle ranges
|
// handle ranges
|
||||||
|
@ -14,7 +14,7 @@ func extractLineNumber(s string) int {
|
||||||
return lineNumber
|
return lineNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
type sortBySeverity []*gosec.Issue
|
type sortBySeverity []*issue.Issue
|
||||||
|
|
||||||
func (s sortBySeverity) Len() int { return len(s) }
|
func (s sortBySeverity) Len() int { return len(s) }
|
||||||
|
|
||||||
|
@ -34,6 +34,6 @@ func (s sortBySeverity) Less(i, j int) bool {
|
||||||
func (s sortBySeverity) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
func (s sortBySeverity) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||||
|
|
||||||
// sortIssues sorts the issues by severity in descending order
|
// sortIssues sorts the issues by severity in descending order
|
||||||
func sortIssues(issues []*gosec.Issue) {
|
func sortIssues(issues []*issue.Issue) {
|
||||||
sort.Sort(sortBySeverity(issues))
|
sort.Sort(sortBySeverity(issues))
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,22 +5,22 @@ import (
|
||||||
|
|
||||||
. "github.com/onsi/ginkgo/v2"
|
. "github.com/onsi/ginkgo/v2"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2/issue"
|
||||||
)
|
)
|
||||||
|
|
||||||
var defaultIssue = gosec.Issue{
|
var defaultIssue = issue.Issue{
|
||||||
File: "/home/src/project/test.go",
|
File: "/home/src/project/test.go",
|
||||||
Line: "1",
|
Line: "1",
|
||||||
Col: "1",
|
Col: "1",
|
||||||
RuleID: "ruleID",
|
RuleID: "ruleID",
|
||||||
What: "test",
|
What: "test",
|
||||||
Confidence: gosec.High,
|
Confidence: issue.High,
|
||||||
Severity: gosec.High,
|
Severity: issue.High,
|
||||||
Code: "1: testcode",
|
Code: "1: testcode",
|
||||||
Cwe: gosec.GetCweByRule("G101"),
|
Cwe: issue.GetCweByRule("G101"),
|
||||||
}
|
}
|
||||||
|
|
||||||
func createIssue() gosec.Issue {
|
func createIssue() issue.Issue {
|
||||||
return defaultIssue
|
return defaultIssue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,8 +29,8 @@ func TestRules(t *testing.T) {
|
||||||
RunSpecs(t, "Sort issues Suite")
|
RunSpecs(t, "Sort issues Suite")
|
||||||
}
|
}
|
||||||
|
|
||||||
func firstIsGreater(less, greater *gosec.Issue) {
|
func firstIsGreater(less, greater *issue.Issue) {
|
||||||
slice := []*gosec.Issue{less, greater}
|
slice := []*issue.Issue{less, greater}
|
||||||
|
|
||||||
sortIssues(slice)
|
sortIssues(slice)
|
||||||
|
|
||||||
|
@ -40,9 +40,9 @@ func firstIsGreater(less, greater *gosec.Issue) {
|
||||||
var _ = Describe("Sorting by Severity", func() {
|
var _ = Describe("Sorting by Severity", func() {
|
||||||
It("sorts by severity", func() {
|
It("sorts by severity", func() {
|
||||||
less := createIssue()
|
less := createIssue()
|
||||||
less.Severity = gosec.Low
|
less.Severity = issue.Low
|
||||||
greater := createIssue()
|
greater := createIssue()
|
||||||
less.Severity = gosec.High
|
less.Severity = issue.High
|
||||||
firstIsGreater(&less, &greater)
|
firstIsGreater(&less, &greater)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -9,5 +9,6 @@ import (
|
||||||
"go/ast"
|
"go/ast"
|
||||||
|
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
)
|
)
|
||||||
`))
|
`))
|
||||||
|
|
|
@ -7,7 +7,7 @@ var generatedRuleTmpl = template.Must(template.New("generated").Parse(`
|
||||||
// DO NOT EDIT - generated by tlsconfig tool
|
// DO NOT EDIT - generated by tlsconfig tool
|
||||||
func New{{.Name}}TLSCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
func New{{.Name}}TLSCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||||
return &insecureConfigTLS{
|
return &insecureConfigTLS{
|
||||||
MetaData: gosec.MetaData{ID: id},
|
MetaData: issue.MetaData{ID: id},
|
||||||
requiredType: "crypto/tls.Config",
|
requiredType: "crypto/tls.Config",
|
||||||
MinVersion: {{ .MinVersion }},
|
MinVersion: {{ .MinVersion }},
|
||||||
MaxVersion: {{ .MaxVersion }},
|
MaxVersion: {{ .MaxVersion }},
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
package gosec
|
package issue
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
@ -105,8 +105,15 @@ type Issue struct {
|
||||||
Suppressions []SuppressionInfo `json:"suppressions"` // Suppression info of the issue
|
Suppressions []SuppressionInfo `json:"suppressions"` // Suppression info of the issue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SuppressionInfo object is to record the kind and the justification that used
|
||||||
|
// to suppress violations.
|
||||||
|
type SuppressionInfo struct {
|
||||||
|
Kind string `json:"kind"`
|
||||||
|
Justification string `json:"justification"`
|
||||||
|
}
|
||||||
|
|
||||||
// FileLocation point out the file path and line number in file
|
// FileLocation point out the file path and line number in file
|
||||||
func (i Issue) FileLocation() string {
|
func (i *Issue) FileLocation() string {
|
||||||
return fmt.Sprintf("%s:%s", i.File, i.Line)
|
return fmt.Sprintf("%s:%s", i.File, i.Line)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,9 +178,8 @@ func codeSnippetEndLine(node ast.Node, fobj *token.File) int64 {
|
||||||
return e + SnippetOffset
|
return e + SnippetOffset
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewIssue creates a new Issue
|
// New creates a new Issue
|
||||||
func NewIssue(ctx *Context, node ast.Node, ruleID, desc string, severity Score, confidence Score) *Issue {
|
func New(fobj *token.File, node ast.Node, ruleID, desc string, severity, confidence Score) *Issue {
|
||||||
fobj := ctx.FileSet.File(node.Pos())
|
|
||||||
name := fobj.Name()
|
name := fobj.Name()
|
||||||
start, end := fobj.Line(node.Pos()), fobj.Line(node.End())
|
start, end := fobj.Line(node.Pos()), fobj.Line(node.End())
|
||||||
line := strconv.Itoa(start)
|
line := strconv.Itoa(start)
|
|
@ -1,4 +1,4 @@
|
||||||
package gosec_test
|
package issue_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go/ast"
|
"go/ast"
|
||||||
|
@ -6,6 +6,7 @@ import (
|
||||||
. "github.com/onsi/ginkgo/v2"
|
. "github.com/onsi/ginkgo/v2"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
"github.com/securego/gosec/v2/rules"
|
"github.com/securego/gosec/v2/rules"
|
||||||
"github.com/securego/gosec/v2/testutils"
|
"github.com/securego/gosec/v2/testutils"
|
||||||
)
|
)
|
||||||
|
@ -36,7 +37,8 @@ var _ = Describe("Issue", func() {
|
||||||
ast.Walk(v, ctx.Root)
|
ast.Walk(v, ctx.Root)
|
||||||
Expect(target).ShouldNot(BeNil())
|
Expect(target).ShouldNot(BeNil())
|
||||||
|
|
||||||
issue := gosec.NewIssue(ctx, target, "TEST", "", gosec.High, gosec.High)
|
fobj := ctx.GetFileAtNodePos(target)
|
||||||
|
issue := issue.New(fobj, target, "TEST", "", issue.High, issue.High)
|
||||||
Expect(issue).ShouldNot(BeNil())
|
Expect(issue).ShouldNot(BeNil())
|
||||||
Expect(issue.Code).Should(MatchRegexp(`"bar"`))
|
Expect(issue.Code).Should(MatchRegexp(`"bar"`))
|
||||||
Expect(issue.Line).Should(Equal("2"))
|
Expect(issue.Line).Should(Equal("2"))
|
||||||
|
@ -79,10 +81,10 @@ var _ = Describe("Issue", func() {
|
||||||
// Use hardcodeded rule to check assignment
|
// Use hardcodeded rule to check assignment
|
||||||
cfg := gosec.NewConfig()
|
cfg := gosec.NewConfig()
|
||||||
rule, _ := rules.NewHardcodedCredentials("TEST", cfg)
|
rule, _ := rules.NewHardcodedCredentials("TEST", cfg)
|
||||||
issue, err := rule.Match(target, ctx)
|
foundIssue, err := rule.Match(target, ctx)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
Expect(err).ShouldNot(HaveOccurred())
|
||||||
Expect(issue).ShouldNot(BeNil())
|
Expect(foundIssue).ShouldNot(BeNil())
|
||||||
Expect(issue.FileLocation()).Should(MatchRegexp("foo.go:5"))
|
Expect(foundIssue.FileLocation()).Should(MatchRegexp("foo.go:5"))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("should provide accurate line and file information", func() {
|
It("should provide accurate line and file information", func() {
|
|
@ -1,15 +1,19 @@
|
||||||
package gosec
|
package gosec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
|
)
|
||||||
|
|
||||||
// ReportInfo this is report information
|
// ReportInfo this is report information
|
||||||
type ReportInfo struct {
|
type ReportInfo struct {
|
||||||
Errors map[string][]Error `json:"Golang errors"`
|
Errors map[string][]Error `json:"Golang errors"`
|
||||||
Issues []*Issue
|
Issues []*issue.Issue
|
||||||
Stats *Metrics
|
Stats *Metrics
|
||||||
GosecVersion string
|
GosecVersion string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewReportInfo instantiate a ReportInfo
|
// NewReportInfo instantiate a ReportInfo
|
||||||
func NewReportInfo(issues []*Issue, metrics *Metrics, errors map[string][]Error) *ReportInfo {
|
func NewReportInfo(issues []*issue.Issue, metrics *Metrics, errors map[string][]Error) *ReportInfo {
|
||||||
return &ReportInfo{
|
return &ReportInfo{
|
||||||
Errors: errors,
|
Errors: errors,
|
||||||
Issues: issues,
|
Issues: issues,
|
||||||
|
|
|
@ -18,6 +18,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
"github.com/securego/gosec/v2/report/csv"
|
"github.com/securego/gosec/v2/report/csv"
|
||||||
"github.com/securego/gosec/v2/report/golint"
|
"github.com/securego/gosec/v2/report/golint"
|
||||||
"github.com/securego/gosec/v2/report/html"
|
"github.com/securego/gosec/v2/report/html"
|
||||||
|
@ -81,8 +82,8 @@ func CreateReport(w io.Writer, format string, enableColor bool, rootPaths []stri
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func filterOutSuppressedIssues(issues []*gosec.Issue) []*gosec.Issue {
|
func filterOutSuppressedIssues(issues []*issue.Issue) []*issue.Issue {
|
||||||
nonSuppressedIssues := []*gosec.Issue{}
|
nonSuppressedIssues := []*issue.Issue{}
|
||||||
for _, issue := range issues {
|
for _, issue := range issues {
|
||||||
if len(issue.Suppressions) == 0 {
|
if len(issue.Suppressions) == 0 {
|
||||||
nonSuppressedIssues = append(nonSuppressedIssues, issue)
|
nonSuppressedIssues = append(nonSuppressedIssues, issue)
|
||||||
|
|
|
@ -10,39 +10,40 @@ import (
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
"github.com/securego/gosec/v2/cwe"
|
"github.com/securego/gosec/v2/cwe"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
"github.com/securego/gosec/v2/report/junit"
|
"github.com/securego/gosec/v2/report/junit"
|
||||||
"github.com/securego/gosec/v2/report/sonar"
|
"github.com/securego/gosec/v2/report/sonar"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func createIssueWithFileWhat(file, what string) *gosec.Issue {
|
func createIssueWithFileWhat(file, what string) *issue.Issue {
|
||||||
issue := createIssue("i1", gosec.GetCweByRule("G101"))
|
issue := createIssue("i1", issue.GetCweByRule("G101"))
|
||||||
issue.File = file
|
issue.File = file
|
||||||
issue.What = what
|
issue.What = what
|
||||||
return &issue
|
return &issue
|
||||||
}
|
}
|
||||||
|
|
||||||
func createIssue(ruleID string, weakness *cwe.Weakness) gosec.Issue {
|
func createIssue(ruleID string, weakness *cwe.Weakness) issue.Issue {
|
||||||
return gosec.Issue{
|
return issue.Issue{
|
||||||
File: "/home/src/project/test.go",
|
File: "/home/src/project/test.go",
|
||||||
Line: "1",
|
Line: "1",
|
||||||
Col: "1",
|
Col: "1",
|
||||||
RuleID: ruleID,
|
RuleID: ruleID,
|
||||||
What: "test",
|
What: "test",
|
||||||
Confidence: gosec.High,
|
Confidence: issue.High,
|
||||||
Severity: gosec.High,
|
Severity: issue.High,
|
||||||
Code: "1: testcode",
|
Code: "1: testcode",
|
||||||
Cwe: weakness,
|
Cwe: weakness,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func createReportInfo(rule string, weakness *cwe.Weakness) gosec.ReportInfo {
|
func createReportInfo(rule string, weakness *cwe.Weakness) gosec.ReportInfo {
|
||||||
issue := createIssue(rule, weakness)
|
newissue := createIssue(rule, weakness)
|
||||||
metrics := gosec.Metrics{}
|
metrics := gosec.Metrics{}
|
||||||
return gosec.ReportInfo{
|
return gosec.ReportInfo{
|
||||||
Errors: map[string][]gosec.Error{},
|
Errors: map[string][]gosec.Error{},
|
||||||
Issues: []*gosec.Issue{
|
Issues: []*issue.Issue{
|
||||||
&issue,
|
&newissue,
|
||||||
},
|
},
|
||||||
Stats: &metrics,
|
Stats: &metrics,
|
||||||
}
|
}
|
||||||
|
@ -62,7 +63,7 @@ var _ = Describe("Formatter", func() {
|
||||||
It("it should parse the report info", func() {
|
It("it should parse the report info", func() {
|
||||||
data := &gosec.ReportInfo{
|
data := &gosec.ReportInfo{
|
||||||
Errors: map[string][]gosec.Error{},
|
Errors: map[string][]gosec.Error{},
|
||||||
Issues: []*gosec.Issue{
|
Issues: []*issue.Issue{
|
||||||
{
|
{
|
||||||
Severity: 2,
|
Severity: 2,
|
||||||
Confidence: 0,
|
Confidence: 0,
|
||||||
|
@ -110,7 +111,7 @@ var _ = Describe("Formatter", func() {
|
||||||
It("it should parse the report info with files in subfolders", func() {
|
It("it should parse the report info with files in subfolders", func() {
|
||||||
data := &gosec.ReportInfo{
|
data := &gosec.ReportInfo{
|
||||||
Errors: map[string][]gosec.Error{},
|
Errors: map[string][]gosec.Error{},
|
||||||
Issues: []*gosec.Issue{
|
Issues: []*issue.Issue{
|
||||||
{
|
{
|
||||||
Severity: 2,
|
Severity: 2,
|
||||||
Confidence: 0,
|
Confidence: 0,
|
||||||
|
@ -157,7 +158,7 @@ var _ = Describe("Formatter", func() {
|
||||||
It("it should not parse the report info for files from other projects", func() {
|
It("it should not parse the report info for files from other projects", func() {
|
||||||
data := &gosec.ReportInfo{
|
data := &gosec.ReportInfo{
|
||||||
Errors: map[string][]gosec.Error{},
|
Errors: map[string][]gosec.Error{},
|
||||||
Issues: []*gosec.Issue{
|
Issues: []*issue.Issue{
|
||||||
{
|
{
|
||||||
Severity: 2,
|
Severity: 2,
|
||||||
Confidence: 0,
|
Confidence: 0,
|
||||||
|
@ -189,7 +190,7 @@ var _ = Describe("Formatter", func() {
|
||||||
It("it should parse the report info for multiple projects projects", func() {
|
It("it should parse the report info for multiple projects projects", func() {
|
||||||
data := &gosec.ReportInfo{
|
data := &gosec.ReportInfo{
|
||||||
Errors: map[string][]gosec.Error{},
|
Errors: map[string][]gosec.Error{},
|
||||||
Issues: []*gosec.Issue{
|
Issues: []*issue.Issue{
|
||||||
{
|
{
|
||||||
Severity: 2,
|
Severity: 2,
|
||||||
Confidence: 0,
|
Confidence: 0,
|
||||||
|
@ -261,7 +262,7 @@ var _ = Describe("Formatter", func() {
|
||||||
|
|
||||||
Context("When using junit", func() {
|
Context("When using junit", func() {
|
||||||
It("preserves order of issues", func() {
|
It("preserves order of issues", func() {
|
||||||
issues := []*gosec.Issue{createIssueWithFileWhat("i1", "1"), createIssueWithFileWhat("i2", "2"), createIssueWithFileWhat("i3", "1")}
|
issues := []*issue.Issue{createIssueWithFileWhat("i1", "1"), createIssueWithFileWhat("i2", "2"), createIssueWithFileWhat("i3", "1")}
|
||||||
|
|
||||||
junitReport := junit.GenerateReport(&gosec.ReportInfo{Issues: issues})
|
junitReport := junit.GenerateReport(&gosec.ReportInfo{Issues: issues})
|
||||||
|
|
||||||
|
@ -285,12 +286,12 @@ var _ = Describe("Formatter", func() {
|
||||||
|
|
||||||
It("csv formatted report should contain the CWE mapping", func() {
|
It("csv formatted report should contain the CWE mapping", func() {
|
||||||
for _, rule := range grules {
|
for _, rule := range grules {
|
||||||
cwe := gosec.GetCweByRule(rule)
|
cwe := issue.GetCweByRule(rule)
|
||||||
issue := createIssue(rule, cwe)
|
newissue := createIssue(rule, cwe)
|
||||||
error := map[string][]gosec.Error{}
|
error := map[string][]gosec.Error{}
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
reportInfo := gosec.NewReportInfo([]*gosec.Issue{&issue}, &gosec.Metrics{}, error)
|
reportInfo := gosec.NewReportInfo([]*issue.Issue{&newissue}, &gosec.Metrics{}, error)
|
||||||
err := CreateReport(buf, "csv", false, []string{}, reportInfo)
|
err := CreateReport(buf, "csv", false, []string{}, reportInfo)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
Expect(err).ShouldNot(HaveOccurred())
|
||||||
pattern := "/home/src/project/test.go,1,test,HIGH,HIGH,1: testcode,CWE-%s\n"
|
pattern := "/home/src/project/test.go,1,test,HIGH,HIGH,1: testcode,CWE-%s\n"
|
||||||
|
@ -300,12 +301,12 @@ var _ = Describe("Formatter", func() {
|
||||||
})
|
})
|
||||||
It("xml formatted report should contain the CWE mapping", func() {
|
It("xml formatted report should contain the CWE mapping", func() {
|
||||||
for _, rule := range grules {
|
for _, rule := range grules {
|
||||||
cwe := gosec.GetCweByRule(rule)
|
cwe := issue.GetCweByRule(rule)
|
||||||
issue := createIssue(rule, cwe)
|
newissue := createIssue(rule, cwe)
|
||||||
error := map[string][]gosec.Error{}
|
error := map[string][]gosec.Error{}
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
reportInfo := gosec.NewReportInfo([]*gosec.Issue{&issue}, &gosec.Metrics{NumFiles: 0, NumLines: 0, NumNosec: 0, NumFound: 0}, error).WithVersion("v2.7.0")
|
reportInfo := gosec.NewReportInfo([]*issue.Issue{&newissue}, &gosec.Metrics{NumFiles: 0, NumLines: 0, NumNosec: 0, NumFound: 0}, error).WithVersion("v2.7.0")
|
||||||
err := CreateReport(buf, "xml", false, []string{}, reportInfo)
|
err := CreateReport(buf, "xml", false, []string{}, reportInfo)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
Expect(err).ShouldNot(HaveOccurred())
|
||||||
pattern := "Results:\n\n\n[/home/src/project/test.go:1] - %s (CWE-%s): test (Confidence: HIGH, Severity: HIGH)\n > 1: testcode\n\n\n\nSummary:\n Gosec : v2.7.0\n Files : 0\n Lines : 0\n Nosec : 0\n Issues : 0\n\n"
|
pattern := "Results:\n\n\n[/home/src/project/test.go:1] - %s (CWE-%s): test (Confidence: HIGH, Severity: HIGH)\n > 1: testcode\n\n\n\nSummary:\n Gosec : v2.7.0\n Files : 0\n Lines : 0\n Nosec : 0\n Issues : 0\n\n"
|
||||||
|
@ -315,8 +316,8 @@ var _ = Describe("Formatter", func() {
|
||||||
})
|
})
|
||||||
It("json formatted report should contain the CWE mapping", func() {
|
It("json formatted report should contain the CWE mapping", func() {
|
||||||
for _, rule := range grules {
|
for _, rule := range grules {
|
||||||
cwe := gosec.GetCweByRule(rule)
|
cwe := issue.GetCweByRule(rule)
|
||||||
issue := createIssue(rule, cwe)
|
newissue := createIssue(rule, cwe)
|
||||||
error := map[string][]gosec.Error{}
|
error := map[string][]gosec.Error{}
|
||||||
|
|
||||||
data := createReportInfo(rule, cwe)
|
data := createReportInfo(rule, cwe)
|
||||||
|
@ -326,7 +327,7 @@ var _ = Describe("Formatter", func() {
|
||||||
err := enc.Encode(data)
|
err := enc.Encode(data)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
Expect(err).ShouldNot(HaveOccurred())
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
reportInfo := gosec.NewReportInfo([]*gosec.Issue{&issue}, &gosec.Metrics{}, error)
|
reportInfo := gosec.NewReportInfo([]*issue.Issue{&newissue}, &gosec.Metrics{}, error)
|
||||||
err = CreateReport(buf, "json", false, []string{}, reportInfo)
|
err = CreateReport(buf, "json", false, []string{}, reportInfo)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
Expect(err).ShouldNot(HaveOccurred())
|
||||||
result := stripString(buf.String())
|
result := stripString(buf.String())
|
||||||
|
@ -336,8 +337,8 @@ var _ = Describe("Formatter", func() {
|
||||||
})
|
})
|
||||||
It("html formatted report should contain the CWE mapping", func() {
|
It("html formatted report should contain the CWE mapping", func() {
|
||||||
for _, rule := range grules {
|
for _, rule := range grules {
|
||||||
cwe := gosec.GetCweByRule(rule)
|
cwe := issue.GetCweByRule(rule)
|
||||||
issue := createIssue(rule, cwe)
|
newissue := createIssue(rule, cwe)
|
||||||
error := map[string][]gosec.Error{}
|
error := map[string][]gosec.Error{}
|
||||||
|
|
||||||
data := createReportInfo(rule, cwe)
|
data := createReportInfo(rule, cwe)
|
||||||
|
@ -347,7 +348,7 @@ var _ = Describe("Formatter", func() {
|
||||||
err := enc.Encode(data)
|
err := enc.Encode(data)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
Expect(err).ShouldNot(HaveOccurred())
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
reportInfo := gosec.NewReportInfo([]*gosec.Issue{&issue}, &gosec.Metrics{}, error)
|
reportInfo := gosec.NewReportInfo([]*issue.Issue{&newissue}, &gosec.Metrics{}, error)
|
||||||
err = CreateReport(buf, "html", false, []string{}, reportInfo)
|
err = CreateReport(buf, "html", false, []string{}, reportInfo)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
Expect(err).ShouldNot(HaveOccurred())
|
||||||
result := stripString(buf.String())
|
result := stripString(buf.String())
|
||||||
|
@ -357,8 +358,8 @@ var _ = Describe("Formatter", func() {
|
||||||
})
|
})
|
||||||
It("yaml formatted report should contain the CWE mapping", func() {
|
It("yaml formatted report should contain the CWE mapping", func() {
|
||||||
for _, rule := range grules {
|
for _, rule := range grules {
|
||||||
cwe := gosec.GetCweByRule(rule)
|
cwe := issue.GetCweByRule(rule)
|
||||||
issue := createIssue(rule, cwe)
|
newissue := createIssue(rule, cwe)
|
||||||
error := map[string][]gosec.Error{}
|
error := map[string][]gosec.Error{}
|
||||||
|
|
||||||
data := createReportInfo(rule, cwe)
|
data := createReportInfo(rule, cwe)
|
||||||
|
@ -368,7 +369,7 @@ var _ = Describe("Formatter", func() {
|
||||||
err := enc.Encode(data)
|
err := enc.Encode(data)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
Expect(err).ShouldNot(HaveOccurred())
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
reportInfo := gosec.NewReportInfo([]*gosec.Issue{&issue}, &gosec.Metrics{}, error)
|
reportInfo := gosec.NewReportInfo([]*issue.Issue{&newissue}, &gosec.Metrics{}, error)
|
||||||
err = CreateReport(buf, "yaml", false, []string{}, reportInfo)
|
err = CreateReport(buf, "yaml", false, []string{}, reportInfo)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
Expect(err).ShouldNot(HaveOccurred())
|
||||||
result := stripString(buf.String())
|
result := stripString(buf.String())
|
||||||
|
@ -378,8 +379,8 @@ var _ = Describe("Formatter", func() {
|
||||||
})
|
})
|
||||||
It("junit-xml formatted report should contain the CWE mapping", func() {
|
It("junit-xml formatted report should contain the CWE mapping", func() {
|
||||||
for _, rule := range grules {
|
for _, rule := range grules {
|
||||||
cwe := gosec.GetCweByRule(rule)
|
cwe := issue.GetCweByRule(rule)
|
||||||
issue := createIssue(rule, cwe)
|
newissue := createIssue(rule, cwe)
|
||||||
error := map[string][]gosec.Error{}
|
error := map[string][]gosec.Error{}
|
||||||
|
|
||||||
data := createReportInfo(rule, cwe)
|
data := createReportInfo(rule, cwe)
|
||||||
|
@ -389,7 +390,7 @@ var _ = Describe("Formatter", func() {
|
||||||
err := enc.Encode(data)
|
err := enc.Encode(data)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
Expect(err).ShouldNot(HaveOccurred())
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
reportInfo := gosec.NewReportInfo([]*gosec.Issue{&issue}, &gosec.Metrics{}, error)
|
reportInfo := gosec.NewReportInfo([]*issue.Issue{&newissue}, &gosec.Metrics{}, error)
|
||||||
err = CreateReport(buf, "junit-xml", false, []string{}, reportInfo)
|
err = CreateReport(buf, "junit-xml", false, []string{}, reportInfo)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
Expect(err).ShouldNot(HaveOccurred())
|
||||||
expectation := stripString(fmt.Sprintf("[/home/src/project/test.go:1] - test (Confidence: 2, Severity: 2, CWE: %s)", cwe.ID))
|
expectation := stripString(fmt.Sprintf("[/home/src/project/test.go:1] - test (Confidence: 2, Severity: 2, CWE: %s)", cwe.ID))
|
||||||
|
@ -399,8 +400,8 @@ var _ = Describe("Formatter", func() {
|
||||||
})
|
})
|
||||||
It("text formatted report should contain the CWE mapping", func() {
|
It("text formatted report should contain the CWE mapping", func() {
|
||||||
for _, rule := range grules {
|
for _, rule := range grules {
|
||||||
cwe := gosec.GetCweByRule(rule)
|
cwe := issue.GetCweByRule(rule)
|
||||||
issue := createIssue(rule, cwe)
|
newissue := createIssue(rule, cwe)
|
||||||
error := map[string][]gosec.Error{}
|
error := map[string][]gosec.Error{}
|
||||||
|
|
||||||
data := createReportInfo(rule, cwe)
|
data := createReportInfo(rule, cwe)
|
||||||
|
@ -410,7 +411,7 @@ var _ = Describe("Formatter", func() {
|
||||||
err := enc.Encode(data)
|
err := enc.Encode(data)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
Expect(err).ShouldNot(HaveOccurred())
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
reportInfo := gosec.NewReportInfo([]*gosec.Issue{&issue}, &gosec.Metrics{}, error)
|
reportInfo := gosec.NewReportInfo([]*issue.Issue{&newissue}, &gosec.Metrics{}, error)
|
||||||
err = CreateReport(buf, "text", false, []string{}, reportInfo)
|
err = CreateReport(buf, "text", false, []string{}, reportInfo)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
Expect(err).ShouldNot(HaveOccurred())
|
||||||
expectation := stripString(fmt.Sprintf("[/home/src/project/test.go:1] - %s (CWE-%s): test (Confidence: HIGH, Severity: HIGH)", rule, cwe.ID))
|
expectation := stripString(fmt.Sprintf("[/home/src/project/test.go:1] - %s (CWE-%s): test (Confidence: HIGH, Severity: HIGH)", rule, cwe.ID))
|
||||||
|
@ -420,11 +421,11 @@ var _ = Describe("Formatter", func() {
|
||||||
})
|
})
|
||||||
It("sonarqube formatted report shouldn't contain the CWE mapping", func() {
|
It("sonarqube formatted report shouldn't contain the CWE mapping", func() {
|
||||||
for _, rule := range grules {
|
for _, rule := range grules {
|
||||||
cwe := gosec.GetCweByRule(rule)
|
cwe := issue.GetCweByRule(rule)
|
||||||
issue := createIssue(rule, cwe)
|
newissue := createIssue(rule, cwe)
|
||||||
error := map[string][]gosec.Error{}
|
error := map[string][]gosec.Error{}
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
reportInfo := gosec.NewReportInfo([]*gosec.Issue{&issue}, &gosec.Metrics{}, error)
|
reportInfo := gosec.NewReportInfo([]*issue.Issue{&newissue}, &gosec.Metrics{}, error)
|
||||||
err := CreateReport(buf, "sonarqube", false, []string{"/home/src/project"}, reportInfo)
|
err := CreateReport(buf, "sonarqube", false, []string{"/home/src/project"}, reportInfo)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
Expect(err).ShouldNot(HaveOccurred())
|
||||||
|
|
||||||
|
@ -441,12 +442,12 @@ var _ = Describe("Formatter", func() {
|
||||||
})
|
})
|
||||||
It("golint formatted report should contain the CWE mapping", func() {
|
It("golint formatted report should contain the CWE mapping", func() {
|
||||||
for _, rule := range grules {
|
for _, rule := range grules {
|
||||||
cwe := gosec.GetCweByRule(rule)
|
cwe := issue.GetCweByRule(rule)
|
||||||
issue := createIssue(rule, cwe)
|
newissue := createIssue(rule, cwe)
|
||||||
error := map[string][]gosec.Error{}
|
error := map[string][]gosec.Error{}
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
reportInfo := gosec.NewReportInfo([]*gosec.Issue{&issue}, &gosec.Metrics{}, error)
|
reportInfo := gosec.NewReportInfo([]*issue.Issue{&newissue}, &gosec.Metrics{}, error)
|
||||||
err := CreateReport(buf, "golint", false, []string{}, reportInfo)
|
err := CreateReport(buf, "golint", false, []string{}, reportInfo)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
Expect(err).ShouldNot(HaveOccurred())
|
||||||
pattern := "/home/src/project/test.go:1:1: [CWE-%s] test (Rule:%s, Severity:HIGH, Confidence:HIGH)\n"
|
pattern := "/home/src/project/test.go:1:1: [CWE-%s] test (Rule:%s, Severity:HIGH, Confidence:HIGH)\n"
|
||||||
|
@ -456,12 +457,12 @@ var _ = Describe("Formatter", func() {
|
||||||
})
|
})
|
||||||
It("sarif formatted report should contain the CWE mapping", func() {
|
It("sarif formatted report should contain the CWE mapping", func() {
|
||||||
for _, rule := range grules {
|
for _, rule := range grules {
|
||||||
cwe := gosec.GetCweByRule(rule)
|
cwe := issue.GetCweByRule(rule)
|
||||||
issue := createIssue(rule, cwe)
|
newissue := createIssue(rule, cwe)
|
||||||
error := map[string][]gosec.Error{}
|
error := map[string][]gosec.Error{}
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
reportInfo := gosec.NewReportInfo([]*gosec.Issue{&issue}, &gosec.Metrics{}, error).WithVersion("v2.7.0")
|
reportInfo := gosec.NewReportInfo([]*issue.Issue{&newissue}, &gosec.Metrics{}, error).WithVersion("v2.7.0")
|
||||||
err := CreateReport(buf, "sarif", false, []string{}, reportInfo)
|
err := CreateReport(buf, "sarif", false, []string{}, reportInfo)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
Expect(err).ShouldNot(HaveOccurred())
|
||||||
|
|
||||||
|
@ -490,8 +491,8 @@ var _ = Describe("Formatter", func() {
|
||||||
|
|
||||||
Context("When converting suppressed issues", func() {
|
Context("When converting suppressed issues", func() {
|
||||||
ruleID := "G101"
|
ruleID := "G101"
|
||||||
cwe := gosec.GetCweByRule(ruleID)
|
cwe := issue.GetCweByRule(ruleID)
|
||||||
suppressions := []gosec.SuppressionInfo{
|
suppressions := []issue.SuppressionInfo{
|
||||||
{
|
{
|
||||||
Kind: "kind",
|
Kind: "kind",
|
||||||
Justification: "justification",
|
Justification: "justification",
|
||||||
|
@ -502,7 +503,7 @@ var _ = Describe("Formatter", func() {
|
||||||
|
|
||||||
It("text formatted report should contain the suppressed issues", func() {
|
It("text formatted report should contain the suppressed issues", func() {
|
||||||
error := map[string][]gosec.Error{}
|
error := map[string][]gosec.Error{}
|
||||||
reportInfo := gosec.NewReportInfo([]*gosec.Issue{&suppressedIssue}, &gosec.Metrics{}, error)
|
reportInfo := gosec.NewReportInfo([]*issue.Issue{&suppressedIssue}, &gosec.Metrics{}, error)
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
err := CreateReport(buf, "text", false, []string{}, reportInfo)
|
err := CreateReport(buf, "text", false, []string{}, reportInfo)
|
||||||
|
@ -514,7 +515,7 @@ var _ = Describe("Formatter", func() {
|
||||||
|
|
||||||
It("sarif formatted report should contain the suppressed issues", func() {
|
It("sarif formatted report should contain the suppressed issues", func() {
|
||||||
error := map[string][]gosec.Error{}
|
error := map[string][]gosec.Error{}
|
||||||
reportInfo := gosec.NewReportInfo([]*gosec.Issue{&suppressedIssue}, &gosec.Metrics{}, error)
|
reportInfo := gosec.NewReportInfo([]*issue.Issue{&suppressedIssue}, &gosec.Metrics{}, error)
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
err := CreateReport(buf, "sarif", false, []string{}, reportInfo)
|
err := CreateReport(buf, "sarif", false, []string{}, reportInfo)
|
||||||
|
@ -526,7 +527,7 @@ var _ = Describe("Formatter", func() {
|
||||||
|
|
||||||
It("json formatted report should contain the suppressed issues", func() {
|
It("json formatted report should contain the suppressed issues", func() {
|
||||||
error := map[string][]gosec.Error{}
|
error := map[string][]gosec.Error{}
|
||||||
reportInfo := gosec.NewReportInfo([]*gosec.Issue{&suppressedIssue}, &gosec.Metrics{}, error)
|
reportInfo := gosec.NewReportInfo([]*issue.Issue{&suppressedIssue}, &gosec.Metrics{}, error)
|
||||||
|
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
err := CreateReport(buf, "json", false, []string{}, reportInfo)
|
err := CreateReport(buf, "json", false, []string{}, reportInfo)
|
||||||
|
|
|
@ -5,9 +5,10 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
)
|
)
|
||||||
|
|
||||||
func generatePlaintext(issue *gosec.Issue) string {
|
func generatePlaintext(issue *issue.Issue) string {
|
||||||
cweID := "CWE"
|
cweID := "CWE"
|
||||||
if issue.Cwe != nil {
|
if issue.Cwe != nil {
|
||||||
cweID = issue.Cwe.ID
|
cweID = issue.Cwe.ID
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
"github.com/securego/gosec/v2/cwe"
|
"github.com/securego/gosec/v2/cwe"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GenerateReport Convert a gosec report to a Sarif Report
|
// GenerateReport Convert a gosec report to a Sarif Report
|
||||||
|
@ -72,28 +73,28 @@ func GenerateReport(rootPaths []string, data *gosec.ReportInfo) (*Report, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseSarifRule return SARIF rule field struct
|
// parseSarifRule return SARIF rule field struct
|
||||||
func parseSarifRule(issue *gosec.Issue) *ReportingDescriptor {
|
func parseSarifRule(i *issue.Issue) *ReportingDescriptor {
|
||||||
cwe := gosec.GetCweByRule(issue.RuleID)
|
cwe := issue.GetCweByRule(i.RuleID)
|
||||||
name := issue.RuleID
|
name := i.RuleID
|
||||||
if cwe != nil {
|
if cwe != nil {
|
||||||
name = cwe.Name
|
name = cwe.Name
|
||||||
}
|
}
|
||||||
return &ReportingDescriptor{
|
return &ReportingDescriptor{
|
||||||
ID: issue.RuleID,
|
ID: i.RuleID,
|
||||||
Name: name,
|
Name: name,
|
||||||
ShortDescription: NewMultiformatMessageString(issue.What),
|
ShortDescription: NewMultiformatMessageString(i.What),
|
||||||
FullDescription: NewMultiformatMessageString(issue.What),
|
FullDescription: NewMultiformatMessageString(i.What),
|
||||||
Help: NewMultiformatMessageString(fmt.Sprintf("%s\nSeverity: %s\nConfidence: %s\n",
|
Help: NewMultiformatMessageString(fmt.Sprintf("%s\nSeverity: %s\nConfidence: %s\n",
|
||||||
issue.What, issue.Severity.String(), issue.Confidence.String())),
|
i.What, i.Severity.String(), i.Confidence.String())),
|
||||||
Properties: &PropertyBag{
|
Properties: &PropertyBag{
|
||||||
"tags": []string{"security", issue.Severity.String()},
|
"tags": []string{"security", i.Severity.String()},
|
||||||
"precision": strings.ToLower(issue.Confidence.String()),
|
"precision": strings.ToLower(i.Confidence.String()),
|
||||||
},
|
},
|
||||||
DefaultConfiguration: &ReportingConfiguration{
|
DefaultConfiguration: &ReportingConfiguration{
|
||||||
Level: getSarifLevel(issue.Severity.String()),
|
Level: getSarifLevel(i.Severity.String()),
|
||||||
},
|
},
|
||||||
Relationships: []*ReportingDescriptorRelationship{
|
Relationships: []*ReportingDescriptorRelationship{
|
||||||
buildSarifReportingDescriptorRelationship(issue.Cwe),
|
buildSarifReportingDescriptorRelationship(i.Cwe),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -157,27 +158,27 @@ func uuid3(value string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseSarifLocation return SARIF location struct
|
// parseSarifLocation return SARIF location struct
|
||||||
func parseSarifLocation(issue *gosec.Issue, rootPaths []string) (*Location, error) {
|
func parseSarifLocation(i *issue.Issue, rootPaths []string) (*Location, error) {
|
||||||
region, err := parseSarifRegion(issue)
|
region, err := parseSarifRegion(i)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
artifactLocation := parseSarifArtifactLocation(issue, rootPaths)
|
artifactLocation := parseSarifArtifactLocation(i, rootPaths)
|
||||||
return NewLocation(NewPhysicalLocation(artifactLocation, region)), nil
|
return NewLocation(NewPhysicalLocation(artifactLocation, region)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseSarifArtifactLocation(issue *gosec.Issue, rootPaths []string) *ArtifactLocation {
|
func parseSarifArtifactLocation(i *issue.Issue, rootPaths []string) *ArtifactLocation {
|
||||||
var filePath string
|
var filePath string
|
||||||
for _, rootPath := range rootPaths {
|
for _, rootPath := range rootPaths {
|
||||||
if strings.HasPrefix(issue.File, rootPath) {
|
if strings.HasPrefix(i.File, rootPath) {
|
||||||
filePath = strings.Replace(issue.File, rootPath+"/", "", 1)
|
filePath = strings.Replace(i.File, rootPath+"/", "", 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return NewArtifactLocation(filePath)
|
return NewArtifactLocation(filePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseSarifRegion(issue *gosec.Issue) (*Region, error) {
|
func parseSarifRegion(i *issue.Issue) (*Region, error) {
|
||||||
lines := strings.Split(issue.Line, "-")
|
lines := strings.Split(i.Line, "-")
|
||||||
startLine, err := strconv.Atoi(lines[0])
|
startLine, err := strconv.Atoi(lines[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -189,13 +190,13 @@ func parseSarifRegion(issue *gosec.Issue) (*Region, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
col, err := strconv.Atoi(issue.Col)
|
col, err := strconv.Atoi(i.Col)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var code string
|
var code string
|
||||||
line := startLine
|
line := startLine
|
||||||
codeLines := strings.Split(issue.Code, "\n")
|
codeLines := strings.Split(i.Code, "\n")
|
||||||
for _, codeLine := range codeLines {
|
for _, codeLine := range codeLines {
|
||||||
lineStart := fmt.Sprintf("%d:", line)
|
lineStart := fmt.Sprintf("%d:", line)
|
||||||
if strings.HasPrefix(codeLine, lineStart) {
|
if strings.HasPrefix(codeLine, lineStart) {
|
||||||
|
@ -227,7 +228,7 @@ func getSarifLevel(s string) Level {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildSarifSuppressions(suppressions []gosec.SuppressionInfo) []*Suppression {
|
func buildSarifSuppressions(suppressions []issue.SuppressionInfo) []*Suppression {
|
||||||
var sarifSuppressionList []*Suppression
|
var sarifSuppressionList []*Suppression
|
||||||
for _, s := range suppressions {
|
for _, s := range suppressions {
|
||||||
sarifSuppressionList = append(sarifSuppressionList, NewSuppression(s.Kind, s.Justification))
|
sarifSuppressionList = append(sarifSuppressionList, NewSuppression(s.Kind, s.Justification))
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
. "github.com/onsi/ginkgo/v2"
|
. "github.com/onsi/ginkgo/v2"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
"github.com/securego/gosec/v2/report/sarif"
|
"github.com/securego/gosec/v2/report/sarif"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -16,7 +17,7 @@ var _ = Describe("Sarif Formatter", func() {
|
||||||
Context("when converting to Sarif issues", func() {
|
Context("when converting to Sarif issues", func() {
|
||||||
It("sarif formatted report should contain the result", func() {
|
It("sarif formatted report should contain the result", func() {
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
reportInfo := gosec.NewReportInfo([]*gosec.Issue{}, &gosec.Metrics{}, map[string][]gosec.Error{}).WithVersion("v2.7.0")
|
reportInfo := gosec.NewReportInfo([]*issue.Issue{}, &gosec.Metrics{}, map[string][]gosec.Error{}).WithVersion("v2.7.0")
|
||||||
err := sarif.WriteReport(buf, reportInfo, []string{})
|
err := sarif.WriteReport(buf, reportInfo, []string{})
|
||||||
result := buf.String()
|
result := buf.String()
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
Expect(err).ShouldNot(HaveOccurred())
|
||||||
|
@ -25,18 +26,18 @@ var _ = Describe("Sarif Formatter", func() {
|
||||||
|
|
||||||
It("sarif formatted report should contain the suppressed results", func() {
|
It("sarif formatted report should contain the suppressed results", func() {
|
||||||
ruleID := "G101"
|
ruleID := "G101"
|
||||||
cwe := gosec.GetCweByRule(ruleID)
|
cwe := issue.GetCweByRule(ruleID)
|
||||||
suppressedIssue := gosec.Issue{
|
suppressedIssue := issue.Issue{
|
||||||
File: "/home/src/project/test.go",
|
File: "/home/src/project/test.go",
|
||||||
Line: "1",
|
Line: "1",
|
||||||
Col: "1",
|
Col: "1",
|
||||||
RuleID: ruleID,
|
RuleID: ruleID,
|
||||||
What: "test",
|
What: "test",
|
||||||
Confidence: gosec.High,
|
Confidence: issue.High,
|
||||||
Severity: gosec.High,
|
Severity: issue.High,
|
||||||
Code: "1: testcode",
|
Code: "1: testcode",
|
||||||
Cwe: cwe,
|
Cwe: cwe,
|
||||||
Suppressions: []gosec.SuppressionInfo{
|
Suppressions: []issue.SuppressionInfo{
|
||||||
{
|
{
|
||||||
Kind: "kind",
|
Kind: "kind",
|
||||||
Justification: "justification",
|
Justification: "justification",
|
||||||
|
@ -44,7 +45,7 @@ var _ = Describe("Sarif Formatter", func() {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
reportInfo := gosec.NewReportInfo([]*gosec.Issue{&suppressedIssue}, &gosec.Metrics{}, map[string][]gosec.Error{}).WithVersion("v2.7.0")
|
reportInfo := gosec.NewReportInfo([]*issue.Issue{&suppressedIssue}, &gosec.Metrics{}, map[string][]gosec.Error{}).WithVersion("v2.7.0")
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
err := sarif.WriteReport(buf, reportInfo, []string{})
|
err := sarif.WriteReport(buf, reportInfo, []string{})
|
||||||
result := buf.String()
|
result := buf.String()
|
||||||
|
@ -58,54 +59,54 @@ var _ = Describe("Sarif Formatter", func() {
|
||||||
})
|
})
|
||||||
It("sarif formatted report should contain the formatted one line code snippet", func() {
|
It("sarif formatted report should contain the formatted one line code snippet", func() {
|
||||||
ruleID := "G101"
|
ruleID := "G101"
|
||||||
cwe := gosec.GetCweByRule(ruleID)
|
cwe := issue.GetCweByRule(ruleID)
|
||||||
code := "68: \t\t}\n69: \t\tvar data = template.HTML(v.TmplFile)\n70: \t\tisTmpl := true\n"
|
code := "68: \t\t}\n69: \t\tvar data = template.HTML(v.TmplFile)\n70: \t\tisTmpl := true\n"
|
||||||
expectedCode := "var data = template.HTML(v.TmplFile)"
|
expectedCode := "var data = template.HTML(v.TmplFile)"
|
||||||
issue := gosec.Issue{
|
newissue := issue.Issue{
|
||||||
File: "/home/src/project/test.go",
|
File: "/home/src/project/test.go",
|
||||||
Line: "69",
|
Line: "69",
|
||||||
Col: "14",
|
Col: "14",
|
||||||
RuleID: ruleID,
|
RuleID: ruleID,
|
||||||
What: "test",
|
What: "test",
|
||||||
Confidence: gosec.High,
|
Confidence: issue.High,
|
||||||
Severity: gosec.High,
|
Severity: issue.High,
|
||||||
Code: code,
|
Code: code,
|
||||||
Cwe: cwe,
|
Cwe: cwe,
|
||||||
Suppressions: []gosec.SuppressionInfo{
|
Suppressions: []issue.SuppressionInfo{
|
||||||
{
|
{
|
||||||
Kind: "kind",
|
Kind: "kind",
|
||||||
Justification: "justification",
|
Justification: "justification",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
reportInfo := gosec.NewReportInfo([]*gosec.Issue{&issue}, &gosec.Metrics{}, map[string][]gosec.Error{}).WithVersion("v2.7.0")
|
reportInfo := gosec.NewReportInfo([]*issue.Issue{&newissue}, &gosec.Metrics{}, map[string][]gosec.Error{}).WithVersion("v2.7.0")
|
||||||
sarifReport, err := sarif.GenerateReport([]string{}, reportInfo)
|
sarifReport, err := sarif.GenerateReport([]string{}, reportInfo)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
Expect(err).ShouldNot(HaveOccurred())
|
||||||
Expect(sarifReport.Runs[0].Results[0].Locations[0].PhysicalLocation.Region.Snippet.Text).Should(Equal(expectedCode))
|
Expect(sarifReport.Runs[0].Results[0].Locations[0].PhysicalLocation.Region.Snippet.Text).Should(Equal(expectedCode))
|
||||||
})
|
})
|
||||||
It("sarif formatted report should contain the formatted multiple line code snippet", func() {
|
It("sarif formatted report should contain the formatted multiple line code snippet", func() {
|
||||||
ruleID := "G101"
|
ruleID := "G101"
|
||||||
cwe := gosec.GetCweByRule(ruleID)
|
cwe := issue.GetCweByRule(ruleID)
|
||||||
code := "68: }\n69: var data = template.HTML(v.TmplFile)\n70: isTmpl := true\n"
|
code := "68: }\n69: var data = template.HTML(v.TmplFile)\n70: isTmpl := true\n"
|
||||||
expectedCode := "var data = template.HTML(v.TmplFile)\nisTmpl := true\n"
|
expectedCode := "var data = template.HTML(v.TmplFile)\nisTmpl := true\n"
|
||||||
issue := gosec.Issue{
|
newissue := issue.Issue{
|
||||||
File: "/home/src/project/test.go",
|
File: "/home/src/project/test.go",
|
||||||
Line: "69-70",
|
Line: "69-70",
|
||||||
Col: "14",
|
Col: "14",
|
||||||
RuleID: ruleID,
|
RuleID: ruleID,
|
||||||
What: "test",
|
What: "test",
|
||||||
Confidence: gosec.High,
|
Confidence: issue.High,
|
||||||
Severity: gosec.High,
|
Severity: issue.High,
|
||||||
Code: code,
|
Code: code,
|
||||||
Cwe: cwe,
|
Cwe: cwe,
|
||||||
Suppressions: []gosec.SuppressionInfo{
|
Suppressions: []issue.SuppressionInfo{
|
||||||
{
|
{
|
||||||
Kind: "kind",
|
Kind: "kind",
|
||||||
Justification: "justification",
|
Justification: "justification",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
reportInfo := gosec.NewReportInfo([]*gosec.Issue{&issue}, &gosec.Metrics{}, map[string][]gosec.Error{}).WithVersion("v2.7.0")
|
reportInfo := gosec.NewReportInfo([]*issue.Issue{&newissue}, &gosec.Metrics{}, map[string][]gosec.Error{}).WithVersion("v2.7.0")
|
||||||
sarifReport, err := sarif.GenerateReport([]string{}, reportInfo)
|
sarifReport, err := sarif.GenerateReport([]string{}, reportInfo)
|
||||||
Expect(err).ShouldNot(HaveOccurred())
|
Expect(err).ShouldNot(HaveOccurred())
|
||||||
Expect(sarifReport.Runs[0].Results[0].Locations[0].PhysicalLocation.Region.Snippet.Text).Should(Equal(expectedCode))
|
Expect(sarifReport.Runs[0].Results[0].Locations[0].PhysicalLocation.Region.Snippet.Text).Should(Equal(expectedCode))
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -36,7 +37,7 @@ func GenerateReport(rootPaths []string, data *gosec.ReportInfo) (*Report, error)
|
||||||
return si, nil
|
return si, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseFilePath(issue *gosec.Issue, rootPaths []string) string {
|
func parseFilePath(issue *issue.Issue, rootPaths []string) string {
|
||||||
var sonarFilePath string
|
var sonarFilePath string
|
||||||
for _, rootPath := range rootPaths {
|
for _, rootPath := range rootPaths {
|
||||||
if strings.HasPrefix(issue.File, rootPath) {
|
if strings.HasPrefix(issue.File, rootPath) {
|
||||||
|
@ -46,7 +47,7 @@ func parseFilePath(issue *gosec.Issue, rootPaths []string) string {
|
||||||
return sonarFilePath
|
return sonarFilePath
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseTextRange(issue *gosec.Issue) (*TextRange, error) {
|
func parseTextRange(issue *issue.Issue) (*TextRange, error) {
|
||||||
lines := strings.Split(issue.Line, "-")
|
lines := strings.Split(issue.Line, "-")
|
||||||
startLine, err := strconv.Atoi(lines[0])
|
startLine, err := strconv.Atoi(lines[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
. "github.com/onsi/ginkgo/v2"
|
. "github.com/onsi/ginkgo/v2"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
"github.com/securego/gosec/v2/report/sonar"
|
"github.com/securego/gosec/v2/report/sonar"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -14,7 +15,7 @@ var _ = Describe("Sonar Formatter", func() {
|
||||||
It("it should parse the report info", func() {
|
It("it should parse the report info", func() {
|
||||||
data := &gosec.ReportInfo{
|
data := &gosec.ReportInfo{
|
||||||
Errors: map[string][]gosec.Error{},
|
Errors: map[string][]gosec.Error{},
|
||||||
Issues: []*gosec.Issue{
|
Issues: []*issue.Issue{
|
||||||
{
|
{
|
||||||
Severity: 2,
|
Severity: 2,
|
||||||
Confidence: 0,
|
Confidence: 0,
|
||||||
|
@ -62,7 +63,7 @@ var _ = Describe("Sonar Formatter", func() {
|
||||||
It("it should parse the report info with files in subfolders", func() {
|
It("it should parse the report info with files in subfolders", func() {
|
||||||
data := &gosec.ReportInfo{
|
data := &gosec.ReportInfo{
|
||||||
Errors: map[string][]gosec.Error{},
|
Errors: map[string][]gosec.Error{},
|
||||||
Issues: []*gosec.Issue{
|
Issues: []*issue.Issue{
|
||||||
{
|
{
|
||||||
Severity: 2,
|
Severity: 2,
|
||||||
Confidence: 0,
|
Confidence: 0,
|
||||||
|
@ -109,7 +110,7 @@ var _ = Describe("Sonar Formatter", func() {
|
||||||
It("it should not parse the report info for files from other projects", func() {
|
It("it should not parse the report info for files from other projects", func() {
|
||||||
data := &gosec.ReportInfo{
|
data := &gosec.ReportInfo{
|
||||||
Errors: map[string][]gosec.Error{},
|
Errors: map[string][]gosec.Error{},
|
||||||
Issues: []*gosec.Issue{
|
Issues: []*issue.Issue{
|
||||||
{
|
{
|
||||||
Severity: 2,
|
Severity: 2,
|
||||||
Confidence: 0,
|
Confidence: 0,
|
||||||
|
@ -141,7 +142,7 @@ var _ = Describe("Sonar Formatter", func() {
|
||||||
It("it should parse the report info for multiple projects projects", func() {
|
It("it should parse the report info for multiple projects projects", func() {
|
||||||
data := &gosec.ReportInfo{
|
data := &gosec.ReportInfo{
|
||||||
Errors: map[string][]gosec.Error{},
|
Errors: map[string][]gosec.Error{},
|
||||||
Issues: []*gosec.Issue{
|
Issues: []*issue.Issue{
|
||||||
{
|
{
|
||||||
Severity: 2,
|
Severity: 2,
|
||||||
Confidence: 0,
|
Confidence: 0,
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
|
|
||||||
"github.com/gookit/color"
|
"github.com/gookit/color"
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -49,7 +50,7 @@ func plainTextFuncMap(enableColor bool) template.FuncMap {
|
||||||
|
|
||||||
// by default those functions return the given content untouched
|
// by default those functions return the given content untouched
|
||||||
return template.FuncMap{
|
return template.FuncMap{
|
||||||
"highlight": func(t string, s gosec.Score, ignored bool) string {
|
"highlight": func(t string, s issue.Score, ignored bool) string {
|
||||||
return t
|
return t
|
||||||
},
|
},
|
||||||
"danger": fmt.Sprint,
|
"danger": fmt.Sprint,
|
||||||
|
@ -60,14 +61,14 @@ func plainTextFuncMap(enableColor bool) template.FuncMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
// highlight returns content t colored based on Score
|
// highlight returns content t colored based on Score
|
||||||
func highlight(t string, s gosec.Score, ignored bool) string {
|
func highlight(t string, s issue.Score, ignored bool) string {
|
||||||
if ignored {
|
if ignored {
|
||||||
return defaultTheme.Sprint(t)
|
return defaultTheme.Sprint(t)
|
||||||
}
|
}
|
||||||
switch s {
|
switch s {
|
||||||
case gosec.High:
|
case issue.High:
|
||||||
return errorTheme.Sprint(t)
|
return errorTheme.Sprint(t)
|
||||||
case gosec.Medium:
|
case issue.Medium:
|
||||||
return warningTheme.Sprint(t)
|
return warningTheme.Sprint(t)
|
||||||
default:
|
default:
|
||||||
return defaultTheme.Sprint(t)
|
return defaultTheme.Sprint(t)
|
||||||
|
@ -75,7 +76,7 @@ func highlight(t string, s gosec.Score, ignored bool) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// printCodeSnippet prints the code snippet from the issue by adding a marker to the affected line
|
// printCodeSnippet prints the code snippet from the issue by adding a marker to the affected line
|
||||||
func printCodeSnippet(issue *gosec.Issue) string {
|
func printCodeSnippet(issue *issue.Issue) string {
|
||||||
start, end := parseLine(issue.Line)
|
start, end := parseLine(issue.Line)
|
||||||
scanner := bufio.NewScanner(strings.NewReader(issue.Code))
|
scanner := bufio.NewScanner(strings.NewReader(issue.Code))
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
|
|
4
rule.go
4
rule.go
|
@ -15,12 +15,14 @@ package gosec
|
||||||
import (
|
import (
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
)
|
)
|
||||||
|
|
||||||
// The Rule interface used by all rules supported by gosec.
|
// The Rule interface used by all rules supported by gosec.
|
||||||
type Rule interface {
|
type Rule interface {
|
||||||
ID() string
|
ID() string
|
||||||
Match(ast.Node, *Context) (*Issue, error)
|
Match(ast.Node, *Context) (*issue.Issue, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RuleBuilder is used to register a rule definition with the analyzer
|
// RuleBuilder is used to register a rule definition with the analyzer
|
||||||
|
|
11
rule_test.go
11
rule_test.go
|
@ -7,10 +7,11 @@ import (
|
||||||
. "github.com/onsi/ginkgo/v2"
|
. "github.com/onsi/ginkgo/v2"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
)
|
)
|
||||||
|
|
||||||
type mockrule struct {
|
type mockrule struct {
|
||||||
issue *gosec.Issue
|
issue *issue.Issue
|
||||||
err error
|
err error
|
||||||
callback func(n ast.Node, ctx *gosec.Context) bool
|
callback func(n ast.Node, ctx *gosec.Context) bool
|
||||||
}
|
}
|
||||||
|
@ -19,7 +20,7 @@ func (m *mockrule) ID() string {
|
||||||
return "MOCK"
|
return "MOCK"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *mockrule) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, error) {
|
func (m *mockrule) Match(n ast.Node, ctx *gosec.Context) (*issue.Issue, error) {
|
||||||
if m.callback(n, ctx) {
|
if m.callback(n, ctx) {
|
||||||
return m.issue, nil
|
return m.issue, nil
|
||||||
}
|
}
|
||||||
|
@ -42,9 +43,9 @@ var _ = Describe("Rule", func() {
|
||||||
callback: func(n ast.Node, ctx *gosec.Context) bool { return false },
|
callback: func(n ast.Node, ctx *gosec.Context) bool { return false },
|
||||||
}
|
}
|
||||||
dummyIssueRule = &mockrule{
|
dummyIssueRule = &mockrule{
|
||||||
issue: &gosec.Issue{
|
issue: &issue.Issue{
|
||||||
Severity: gosec.High,
|
Severity: issue.High,
|
||||||
Confidence: gosec.High,
|
Confidence: issue.High,
|
||||||
What: `Some explanation of the thing`,
|
What: `Some explanation of the thing`,
|
||||||
File: "main.go",
|
File: "main.go",
|
||||||
Code: `#include <stdio.h> int main(){ puts("hello world"); }`,
|
Code: `#include <stdio.h> int main(){ puts("hello world"); }`,
|
||||||
|
|
|
@ -5,10 +5,11 @@ import (
|
||||||
"go/types"
|
"go/types"
|
||||||
|
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
)
|
)
|
||||||
|
|
||||||
type archive struct {
|
type archive struct {
|
||||||
gosec.MetaData
|
issue.MetaData
|
||||||
calls gosec.CallList
|
calls gosec.CallList
|
||||||
argTypes []string
|
argTypes []string
|
||||||
}
|
}
|
||||||
|
@ -18,7 +19,7 @@ func (a *archive) ID() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Match inspects AST nodes to determine if the filepath.Joins uses any argument derived from type zip.File or tar.Header
|
// Match inspects AST nodes to determine if the filepath.Joins uses any argument derived from type zip.File or tar.Header
|
||||||
func (a *archive) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
|
func (a *archive) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
|
||||||
if node := a.calls.ContainsPkgCallExpr(n, c, false); node != nil {
|
if node := a.calls.ContainsPkgCallExpr(n, c, false); node != nil {
|
||||||
for _, arg := range node.Args {
|
for _, arg := range node.Args {
|
||||||
var argType types.Type
|
var argType types.Type
|
||||||
|
@ -38,7 +39,7 @@ func (a *archive) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
|
||||||
if argType != nil {
|
if argType != nil {
|
||||||
for _, t := range a.argTypes {
|
for _, t := range a.argTypes {
|
||||||
if argType.String() == t {
|
if argType.String() == t {
|
||||||
return gosec.NewIssue(c, n, a.ID(), a.What, a.Severity, a.Confidence), nil
|
return c.NewIssue(n, a.ID(), a.What, a.Severity, a.Confidence), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,10 +56,10 @@ func NewArchive(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||||
return &archive{
|
return &archive{
|
||||||
calls: calls,
|
calls: calls,
|
||||||
argTypes: []string{"*archive/zip.File", "*archive/tar.Header"},
|
argTypes: []string{"*archive/zip.File", "*archive/tar.Header"},
|
||||||
MetaData: gosec.MetaData{
|
MetaData: issue.MetaData{
|
||||||
ID: id,
|
ID: id,
|
||||||
Severity: gosec.Medium,
|
Severity: issue.Medium,
|
||||||
Confidence: gosec.High,
|
Confidence: issue.High,
|
||||||
What: "File traversal when extracting zip/tar archive",
|
What: "File traversal when extracting zip/tar archive",
|
||||||
},
|
},
|
||||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
)
|
)
|
||||||
|
|
||||||
type deferType struct {
|
type deferType struct {
|
||||||
|
@ -14,7 +15,7 @@ type deferType struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type badDefer struct {
|
type badDefer struct {
|
||||||
gosec.MetaData
|
issue.MetaData
|
||||||
types []deferType
|
types []deferType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,12 +36,12 @@ func contains(methods []string, method string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *badDefer) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
|
func (r *badDefer) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
|
||||||
if deferStmt, ok := n.(*ast.DeferStmt); ok {
|
if deferStmt, ok := n.(*ast.DeferStmt); ok {
|
||||||
for _, deferTyp := range r.types {
|
for _, deferTyp := range r.types {
|
||||||
if typ, method, err := gosec.GetCallInfo(deferStmt.Call, c); err == nil {
|
if typ, method, err := gosec.GetCallInfo(deferStmt.Call, c); err == nil {
|
||||||
if normalize(typ) == deferTyp.typ && contains(deferTyp.methods, method) {
|
if normalize(typ) == deferTyp.typ && contains(deferTyp.methods, method) {
|
||||||
return gosec.NewIssue(c, n, r.ID(), fmt.Sprintf(r.What, method, typ), r.Severity, r.Confidence), nil
|
return c.NewIssue(n, r.ID(), fmt.Sprintf(r.What, method, typ), r.Severity, r.Confidence), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,10 +87,10 @@ func NewDeferredClosing(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||||
methods: []string{"Close"},
|
methods: []string{"Close"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
MetaData: gosec.MetaData{
|
MetaData: issue.MetaData{
|
||||||
ID: id,
|
ID: id,
|
||||||
Severity: gosec.Medium,
|
Severity: issue.Medium,
|
||||||
Confidence: gosec.High,
|
Confidence: issue.High,
|
||||||
What: "Deferring unsafe method %q on type %q",
|
What: "Deferring unsafe method %q on type %q",
|
||||||
},
|
},
|
||||||
}, []ast.Node{(*ast.DeferStmt)(nil)}
|
}, []ast.Node{(*ast.DeferStmt)(nil)}
|
||||||
|
|
|
@ -19,11 +19,12 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Looks for net.Listen("0.0.0.0") or net.Listen(":8080")
|
// Looks for net.Listen("0.0.0.0") or net.Listen(":8080")
|
||||||
type bindsToAllNetworkInterfaces struct {
|
type bindsToAllNetworkInterfaces struct {
|
||||||
gosec.MetaData
|
issue.MetaData
|
||||||
calls gosec.CallList
|
calls gosec.CallList
|
||||||
pattern *regexp.Regexp
|
pattern *regexp.Regexp
|
||||||
}
|
}
|
||||||
|
@ -32,7 +33,7 @@ func (r *bindsToAllNetworkInterfaces) ID() string {
|
||||||
return r.MetaData.ID
|
return r.MetaData.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *bindsToAllNetworkInterfaces) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
|
func (r *bindsToAllNetworkInterfaces) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
|
||||||
callExpr := r.calls.ContainsPkgCallExpr(n, c, false)
|
callExpr := r.calls.ContainsPkgCallExpr(n, c, false)
|
||||||
if callExpr == nil {
|
if callExpr == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
@ -42,14 +43,14 @@ func (r *bindsToAllNetworkInterfaces) Match(n ast.Node, c *gosec.Context) (*gose
|
||||||
if bl, ok := arg.(*ast.BasicLit); ok {
|
if bl, ok := arg.(*ast.BasicLit); ok {
|
||||||
if arg, err := gosec.GetString(bl); err == nil {
|
if arg, err := gosec.GetString(bl); err == nil {
|
||||||
if r.pattern.MatchString(arg) {
|
if r.pattern.MatchString(arg) {
|
||||||
return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil
|
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if ident, ok := arg.(*ast.Ident); ok {
|
} else if ident, ok := arg.(*ast.Ident); ok {
|
||||||
values := gosec.GetIdentStringValues(ident)
|
values := gosec.GetIdentStringValues(ident)
|
||||||
for _, value := range values {
|
for _, value := range values {
|
||||||
if r.pattern.MatchString(value) {
|
if r.pattern.MatchString(value) {
|
||||||
return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil
|
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,7 +58,7 @@ func (r *bindsToAllNetworkInterfaces) Match(n ast.Node, c *gosec.Context) (*gose
|
||||||
values := gosec.GetCallStringArgsValues(callExpr.Args[0], c)
|
values := gosec.GetCallStringArgsValues(callExpr.Args[0], c)
|
||||||
for _, value := range values {
|
for _, value := range values {
|
||||||
if r.pattern.MatchString(value) {
|
if r.pattern.MatchString(value) {
|
||||||
return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil
|
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,10 +74,10 @@ func NewBindsToAllNetworkInterfaces(id string, conf gosec.Config) (gosec.Rule, [
|
||||||
return &bindsToAllNetworkInterfaces{
|
return &bindsToAllNetworkInterfaces{
|
||||||
calls: calls,
|
calls: calls,
|
||||||
pattern: regexp.MustCompile(`^(0.0.0.0|:).*$`),
|
pattern: regexp.MustCompile(`^(0.0.0.0|:).*$`),
|
||||||
MetaData: gosec.MetaData{
|
MetaData: issue.MetaData{
|
||||||
ID: id,
|
ID: id,
|
||||||
Severity: gosec.Medium,
|
Severity: issue.Medium,
|
||||||
Confidence: gosec.High,
|
Confidence: issue.High,
|
||||||
What: "Binds to all network interfaces",
|
What: "Binds to all network interfaces",
|
||||||
},
|
},
|
||||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||||
|
|
|
@ -19,10 +19,11 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
)
|
)
|
||||||
|
|
||||||
type blocklistedImport struct {
|
type blocklistedImport struct {
|
||||||
gosec.MetaData
|
issue.MetaData
|
||||||
Blocklisted map[string]string
|
Blocklisted map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,10 +37,10 @@ func (r *blocklistedImport) ID() string {
|
||||||
return r.MetaData.ID
|
return r.MetaData.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *blocklistedImport) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
|
func (r *blocklistedImport) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
|
||||||
if node, ok := n.(*ast.ImportSpec); ok {
|
if node, ok := n.(*ast.ImportSpec); ok {
|
||||||
if description, ok := r.Blocklisted[unquote(node.Path.Value)]; ok {
|
if description, ok := r.Blocklisted[unquote(node.Path.Value)]; ok {
|
||||||
return gosec.NewIssue(c, node, r.ID(), description, r.Severity, r.Confidence), nil
|
return c.NewIssue(node, r.ID(), description, r.Severity, r.Confidence), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
@ -49,10 +50,10 @@ func (r *blocklistedImport) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, e
|
||||||
// Typically when a deprecated technology is being used.
|
// Typically when a deprecated technology is being used.
|
||||||
func NewBlocklistedImports(id string, conf gosec.Config, blocklist map[string]string) (gosec.Rule, []ast.Node) {
|
func NewBlocklistedImports(id string, conf gosec.Config, blocklist map[string]string) (gosec.Rule, []ast.Node) {
|
||||||
return &blocklistedImport{
|
return &blocklistedImport{
|
||||||
MetaData: gosec.MetaData{
|
MetaData: issue.MetaData{
|
||||||
ID: id,
|
ID: id,
|
||||||
Severity: gosec.Medium,
|
Severity: issue.Medium,
|
||||||
Confidence: gosec.High,
|
Confidence: issue.High,
|
||||||
},
|
},
|
||||||
Blocklisted: blocklist,
|
Blocklisted: blocklist,
|
||||||
}, []ast.Node{(*ast.ImportSpec)(nil)}
|
}, []ast.Node{(*ast.ImportSpec)(nil)}
|
||||||
|
|
|
@ -19,10 +19,11 @@ import (
|
||||||
"go/ast"
|
"go/ast"
|
||||||
|
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
)
|
)
|
||||||
|
|
||||||
type decompressionBombCheck struct {
|
type decompressionBombCheck struct {
|
||||||
gosec.MetaData
|
issue.MetaData
|
||||||
readerCalls gosec.CallList
|
readerCalls gosec.CallList
|
||||||
copyCalls gosec.CallList
|
copyCalls gosec.CallList
|
||||||
}
|
}
|
||||||
|
@ -40,7 +41,7 @@ func containsReaderCall(node ast.Node, ctx *gosec.Context, list gosec.CallList)
|
||||||
return list.Contains(s, idt)
|
return list.Contains(s, idt)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *decompressionBombCheck) Match(node ast.Node, ctx *gosec.Context) (*gosec.Issue, error) {
|
func (d *decompressionBombCheck) Match(node ast.Node, ctx *gosec.Context) (*issue.Issue, error) {
|
||||||
var readerVarObj map[*ast.Object]struct{}
|
var readerVarObj map[*ast.Object]struct{}
|
||||||
|
|
||||||
// To check multiple lines, ctx.PassedValues is used to store temporary data.
|
// To check multiple lines, ctx.PassedValues is used to store temporary data.
|
||||||
|
@ -72,7 +73,7 @@ func (d *decompressionBombCheck) Match(node ast.Node, ctx *gosec.Context) (*gose
|
||||||
if idt, ok := n.Args[1].(*ast.Ident); ok {
|
if idt, ok := n.Args[1].(*ast.Ident); ok {
|
||||||
if _, ok := readerVarObj[idt.Obj]; ok {
|
if _, ok := readerVarObj[idt.Obj]; ok {
|
||||||
// Detect io.Copy(x, r)
|
// Detect io.Copy(x, r)
|
||||||
return gosec.NewIssue(ctx, n, d.ID(), d.What, d.Severity, d.Confidence), nil
|
return ctx.NewIssue(n, d.ID(), d.What, d.Severity, d.Confidence), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,10 +99,10 @@ func NewDecompressionBombCheck(id string, conf gosec.Config) (gosec.Rule, []ast.
|
||||||
copyCalls.Add("io", "CopyBuffer")
|
copyCalls.Add("io", "CopyBuffer")
|
||||||
|
|
||||||
return &decompressionBombCheck{
|
return &decompressionBombCheck{
|
||||||
MetaData: gosec.MetaData{
|
MetaData: issue.MetaData{
|
||||||
ID: id,
|
ID: id,
|
||||||
Severity: gosec.Medium,
|
Severity: issue.Medium,
|
||||||
Confidence: gosec.Medium,
|
Confidence: issue.Medium,
|
||||||
What: "Potential DoS vulnerability via decompression bomb",
|
What: "Potential DoS vulnerability via decompression bomb",
|
||||||
},
|
},
|
||||||
readerCalls: readerCalls,
|
readerCalls: readerCalls,
|
||||||
|
|
|
@ -5,18 +5,19 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
)
|
)
|
||||||
|
|
||||||
type traversal struct {
|
type traversal struct {
|
||||||
pattern *regexp.Regexp
|
pattern *regexp.Regexp
|
||||||
gosec.MetaData
|
issue.MetaData
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *traversal) ID() string {
|
func (r *traversal) ID() string {
|
||||||
return r.MetaData.ID
|
return r.MetaData.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *traversal) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, error) {
|
func (r *traversal) Match(n ast.Node, ctx *gosec.Context) (*issue.Issue, error) {
|
||||||
switch node := n.(type) {
|
switch node := n.(type) {
|
||||||
case *ast.CallExpr:
|
case *ast.CallExpr:
|
||||||
return r.matchCallExpr(node, ctx)
|
return r.matchCallExpr(node, ctx)
|
||||||
|
@ -24,14 +25,14 @@ func (r *traversal) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, error)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *traversal) matchCallExpr(assign *ast.CallExpr, ctx *gosec.Context) (*gosec.Issue, error) {
|
func (r *traversal) matchCallExpr(assign *ast.CallExpr, ctx *gosec.Context) (*issue.Issue, error) {
|
||||||
for _, i := range assign.Args {
|
for _, i := range assign.Args {
|
||||||
if basiclit, ok1 := i.(*ast.BasicLit); ok1 {
|
if basiclit, ok1 := i.(*ast.BasicLit); ok1 {
|
||||||
if fun, ok2 := assign.Fun.(*ast.SelectorExpr); ok2 {
|
if fun, ok2 := assign.Fun.(*ast.SelectorExpr); ok2 {
|
||||||
if x, ok3 := fun.X.(*ast.Ident); ok3 {
|
if x, ok3 := fun.X.(*ast.Ident); ok3 {
|
||||||
string := x.Name + "." + fun.Sel.Name + "(" + basiclit.Value + ")"
|
string := x.Name + "." + fun.Sel.Name + "(" + basiclit.Value + ")"
|
||||||
if r.pattern.MatchString(string) {
|
if r.pattern.MatchString(string) {
|
||||||
return gosec.NewIssue(ctx, assign, r.ID(), r.What, r.Severity, r.Confidence), nil
|
return ctx.NewIssue(assign, r.ID(), r.What, r.Severity, r.Confidence), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -54,11 +55,11 @@ func NewDirectoryTraversal(id string, conf gosec.Config) (gosec.Rule, []ast.Node
|
||||||
|
|
||||||
return &traversal{
|
return &traversal{
|
||||||
pattern: regexp.MustCompile(pattern),
|
pattern: regexp.MustCompile(pattern),
|
||||||
MetaData: gosec.MetaData{
|
MetaData: issue.MetaData{
|
||||||
ID: id,
|
ID: id,
|
||||||
What: "Potential directory traversal",
|
What: "Potential directory traversal",
|
||||||
Confidence: gosec.Medium,
|
Confidence: issue.Medium,
|
||||||
Severity: gosec.Medium,
|
Severity: issue.Medium,
|
||||||
},
|
},
|
||||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,10 +19,11 @@ import (
|
||||||
"go/types"
|
"go/types"
|
||||||
|
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
)
|
)
|
||||||
|
|
||||||
type noErrorCheck struct {
|
type noErrorCheck struct {
|
||||||
gosec.MetaData
|
issue.MetaData
|
||||||
whitelist gosec.CallList
|
whitelist gosec.CallList
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,7 +50,7 @@ func returnsError(callExpr *ast.CallExpr, ctx *gosec.Context) int {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *noErrorCheck) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, error) {
|
func (r *noErrorCheck) Match(n ast.Node, ctx *gosec.Context) (*issue.Issue, error) {
|
||||||
switch stmt := n.(type) {
|
switch stmt := n.(type) {
|
||||||
case *ast.AssignStmt:
|
case *ast.AssignStmt:
|
||||||
cfg := ctx.Config
|
cfg := ctx.Config
|
||||||
|
@ -61,7 +62,7 @@ func (r *noErrorCheck) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, erro
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
if id, ok := stmt.Lhs[pos].(*ast.Ident); ok && id.Name == "_" {
|
if id, ok := stmt.Lhs[pos].(*ast.Ident); ok && id.Name == "_" {
|
||||||
return gosec.NewIssue(ctx, n, r.ID(), r.What, r.Severity, r.Confidence), nil
|
return ctx.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,7 +71,7 @@ func (r *noErrorCheck) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, erro
|
||||||
if callExpr, ok := stmt.X.(*ast.CallExpr); ok && r.whitelist.ContainsCallExpr(stmt.X, ctx) == nil {
|
if callExpr, ok := stmt.X.(*ast.CallExpr); ok && r.whitelist.ContainsCallExpr(stmt.X, ctx) == nil {
|
||||||
pos := returnsError(callExpr, ctx)
|
pos := returnsError(callExpr, ctx)
|
||||||
if pos >= 0 {
|
if pos >= 0 {
|
||||||
return gosec.NewIssue(ctx, n, r.ID(), r.What, r.Severity, r.Confidence), nil
|
return ctx.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,10 +101,10 @@ func NewNoErrorCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return &noErrorCheck{
|
return &noErrorCheck{
|
||||||
MetaData: gosec.MetaData{
|
MetaData: issue.MetaData{
|
||||||
ID: id,
|
ID: id,
|
||||||
Severity: gosec.Low,
|
Severity: issue.Low,
|
||||||
Confidence: gosec.High,
|
Confidence: issue.High,
|
||||||
What: "Errors unhandled.",
|
What: "Errors unhandled.",
|
||||||
},
|
},
|
||||||
whitelist: whitelist,
|
whitelist: whitelist,
|
||||||
|
|
|
@ -20,10 +20,11 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
)
|
)
|
||||||
|
|
||||||
type filePermissions struct {
|
type filePermissions struct {
|
||||||
gosec.MetaData
|
issue.MetaData
|
||||||
mode int64
|
mode int64
|
||||||
pkgs []string
|
pkgs []string
|
||||||
calls []string
|
calls []string
|
||||||
|
@ -54,12 +55,12 @@ func modeIsSubset(subset int64, superset int64) bool {
|
||||||
return (subset | superset) == superset
|
return (subset | superset) == superset
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *filePermissions) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
|
func (r *filePermissions) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
|
||||||
for _, pkg := range r.pkgs {
|
for _, pkg := range r.pkgs {
|
||||||
if callexpr, matched := gosec.MatchCallByPackage(n, c, pkg, r.calls...); matched {
|
if callexpr, matched := gosec.MatchCallByPackage(n, c, pkg, r.calls...); matched {
|
||||||
modeArg := callexpr.Args[len(callexpr.Args)-1]
|
modeArg := callexpr.Args[len(callexpr.Args)-1]
|
||||||
if mode, err := gosec.GetInt(modeArg); err == nil && !modeIsSubset(mode, r.mode) {
|
if mode, err := gosec.GetInt(modeArg); err == nil && !modeIsSubset(mode, r.mode) {
|
||||||
return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil
|
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,10 +74,10 @@ func NewWritePerms(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||||
mode: mode,
|
mode: mode,
|
||||||
pkgs: []string{"io/ioutil", "os"},
|
pkgs: []string{"io/ioutil", "os"},
|
||||||
calls: []string{"WriteFile"},
|
calls: []string{"WriteFile"},
|
||||||
MetaData: gosec.MetaData{
|
MetaData: issue.MetaData{
|
||||||
ID: id,
|
ID: id,
|
||||||
Severity: gosec.Medium,
|
Severity: issue.Medium,
|
||||||
Confidence: gosec.High,
|
Confidence: issue.High,
|
||||||
What: fmt.Sprintf("Expect WriteFile permissions to be %#o or less", mode),
|
What: fmt.Sprintf("Expect WriteFile permissions to be %#o or less", mode),
|
||||||
},
|
},
|
||||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||||
|
@ -90,10 +91,10 @@ func NewFilePerms(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||||
mode: mode,
|
mode: mode,
|
||||||
pkgs: []string{"os"},
|
pkgs: []string{"os"},
|
||||||
calls: []string{"OpenFile", "Chmod"},
|
calls: []string{"OpenFile", "Chmod"},
|
||||||
MetaData: gosec.MetaData{
|
MetaData: issue.MetaData{
|
||||||
ID: id,
|
ID: id,
|
||||||
Severity: gosec.Medium,
|
Severity: issue.Medium,
|
||||||
Confidence: gosec.High,
|
Confidence: issue.High,
|
||||||
What: fmt.Sprintf("Expect file permissions to be %#o or less", mode),
|
What: fmt.Sprintf("Expect file permissions to be %#o or less", mode),
|
||||||
},
|
},
|
||||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||||
|
@ -107,10 +108,10 @@ func NewMkdirPerms(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||||
mode: mode,
|
mode: mode,
|
||||||
pkgs: []string{"os"},
|
pkgs: []string{"os"},
|
||||||
calls: []string{"Mkdir", "MkdirAll"},
|
calls: []string{"Mkdir", "MkdirAll"},
|
||||||
MetaData: gosec.MetaData{
|
MetaData: issue.MetaData{
|
||||||
ID: id,
|
ID: id,
|
||||||
Severity: gosec.Medium,
|
Severity: issue.Medium,
|
||||||
Confidence: gosec.High,
|
Confidence: issue.High,
|
||||||
What: fmt.Sprintf("Expect directory permissions to be %#o or less", mode),
|
What: fmt.Sprintf("Expect directory permissions to be %#o or less", mode),
|
||||||
},
|
},
|
||||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||||
|
|
|
@ -22,10 +22,11 @@ import (
|
||||||
|
|
||||||
zxcvbn "github.com/nbutton23/zxcvbn-go"
|
zxcvbn "github.com/nbutton23/zxcvbn-go"
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
)
|
)
|
||||||
|
|
||||||
type credentials struct {
|
type credentials struct {
|
||||||
gosec.MetaData
|
issue.MetaData
|
||||||
pattern *regexp.Regexp
|
pattern *regexp.Regexp
|
||||||
entropyThreshold float64
|
entropyThreshold float64
|
||||||
perCharThreshold float64
|
perCharThreshold float64
|
||||||
|
@ -53,7 +54,7 @@ func (r *credentials) isHighEntropyString(str string) bool {
|
||||||
entropyPerChar >= r.perCharThreshold))
|
entropyPerChar >= r.perCharThreshold))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *credentials) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, error) {
|
func (r *credentials) Match(n ast.Node, ctx *gosec.Context) (*issue.Issue, error) {
|
||||||
switch node := n.(type) {
|
switch node := n.(type) {
|
||||||
case *ast.AssignStmt:
|
case *ast.AssignStmt:
|
||||||
return r.matchAssign(node, ctx)
|
return r.matchAssign(node, ctx)
|
||||||
|
@ -65,14 +66,14 @@ func (r *credentials) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, error
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *credentials) matchAssign(assign *ast.AssignStmt, ctx *gosec.Context) (*gosec.Issue, error) {
|
func (r *credentials) matchAssign(assign *ast.AssignStmt, ctx *gosec.Context) (*issue.Issue, error) {
|
||||||
for _, i := range assign.Lhs {
|
for _, i := range assign.Lhs {
|
||||||
if ident, ok := i.(*ast.Ident); ok {
|
if ident, ok := i.(*ast.Ident); ok {
|
||||||
if r.pattern.MatchString(ident.Name) {
|
if r.pattern.MatchString(ident.Name) {
|
||||||
for _, e := range assign.Rhs {
|
for _, e := range assign.Rhs {
|
||||||
if val, err := gosec.GetString(e); err == nil {
|
if val, err := gosec.GetString(e); err == nil {
|
||||||
if r.ignoreEntropy || (!r.ignoreEntropy && r.isHighEntropyString(val)) {
|
if r.ignoreEntropy || (!r.ignoreEntropy && r.isHighEntropyString(val)) {
|
||||||
return gosec.NewIssue(ctx, assign, r.ID(), r.What, r.Severity, r.Confidence), nil
|
return ctx.NewIssue(assign, r.ID(), r.What, r.Severity, r.Confidence), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,7 +83,7 @@ func (r *credentials) matchAssign(assign *ast.AssignStmt, ctx *gosec.Context) (*
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *credentials) matchValueSpec(valueSpec *ast.ValueSpec, ctx *gosec.Context) (*gosec.Issue, error) {
|
func (r *credentials) matchValueSpec(valueSpec *ast.ValueSpec, ctx *gosec.Context) (*issue.Issue, error) {
|
||||||
for index, ident := range valueSpec.Names {
|
for index, ident := range valueSpec.Names {
|
||||||
if r.pattern.MatchString(ident.Name) && valueSpec.Values != nil {
|
if r.pattern.MatchString(ident.Name) && valueSpec.Values != nil {
|
||||||
// const foo, bar = "same value"
|
// const foo, bar = "same value"
|
||||||
|
@ -91,7 +92,7 @@ func (r *credentials) matchValueSpec(valueSpec *ast.ValueSpec, ctx *gosec.Contex
|
||||||
}
|
}
|
||||||
if val, err := gosec.GetString(valueSpec.Values[index]); err == nil {
|
if val, err := gosec.GetString(valueSpec.Values[index]); err == nil {
|
||||||
if r.ignoreEntropy || (!r.ignoreEntropy && r.isHighEntropyString(val)) {
|
if r.ignoreEntropy || (!r.ignoreEntropy && r.isHighEntropyString(val)) {
|
||||||
return gosec.NewIssue(ctx, valueSpec, r.ID(), r.What, r.Severity, r.Confidence), nil
|
return ctx.NewIssue(valueSpec, r.ID(), r.What, r.Severity, r.Confidence), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,7 +100,7 @@ func (r *credentials) matchValueSpec(valueSpec *ast.ValueSpec, ctx *gosec.Contex
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *credentials) matchEqualityCheck(binaryExpr *ast.BinaryExpr, ctx *gosec.Context) (*gosec.Issue, error) {
|
func (r *credentials) matchEqualityCheck(binaryExpr *ast.BinaryExpr, ctx *gosec.Context) (*issue.Issue, error) {
|
||||||
if binaryExpr.Op == token.EQL || binaryExpr.Op == token.NEQ {
|
if binaryExpr.Op == token.EQL || binaryExpr.Op == token.NEQ {
|
||||||
ident, ok := binaryExpr.X.(*ast.Ident)
|
ident, ok := binaryExpr.X.(*ast.Ident)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -113,7 +114,7 @@ func (r *credentials) matchEqualityCheck(binaryExpr *ast.BinaryExpr, ctx *gosec.
|
||||||
}
|
}
|
||||||
if val, err := gosec.GetString(valueNode); err == nil {
|
if val, err := gosec.GetString(valueNode); err == nil {
|
||||||
if r.ignoreEntropy || (!r.ignoreEntropy && r.isHighEntropyString(val)) {
|
if r.ignoreEntropy || (!r.ignoreEntropy && r.isHighEntropyString(val)) {
|
||||||
return gosec.NewIssue(ctx, binaryExpr, r.ID(), r.What, r.Severity, r.Confidence), nil
|
return ctx.NewIssue(binaryExpr, r.ID(), r.What, r.Severity, r.Confidence), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -170,11 +171,11 @@ func NewHardcodedCredentials(id string, conf gosec.Config) (gosec.Rule, []ast.No
|
||||||
perCharThreshold: perCharThreshold,
|
perCharThreshold: perCharThreshold,
|
||||||
ignoreEntropy: ignoreEntropy,
|
ignoreEntropy: ignoreEntropy,
|
||||||
truncate: truncateString,
|
truncate: truncateString,
|
||||||
MetaData: gosec.MetaData{
|
MetaData: issue.MetaData{
|
||||||
ID: id,
|
ID: id,
|
||||||
What: "Potential hardcoded credentials",
|
What: "Potential hardcoded credentials",
|
||||||
Confidence: gosec.Low,
|
Confidence: issue.Low,
|
||||||
Severity: gosec.High,
|
Severity: issue.High,
|
||||||
},
|
},
|
||||||
}, []ast.Node{(*ast.AssignStmt)(nil), (*ast.ValueSpec)(nil), (*ast.BinaryExpr)(nil)}
|
}, []ast.Node{(*ast.AssignStmt)(nil), (*ast.ValueSpec)(nil), (*ast.BinaryExpr)(nil)}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,11 @@ import (
|
||||||
"go/ast"
|
"go/ast"
|
||||||
|
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
)
|
)
|
||||||
|
|
||||||
type httpServeWithoutTimeouts struct {
|
type httpServeWithoutTimeouts struct {
|
||||||
gosec.MetaData
|
issue.MetaData
|
||||||
pkg string
|
pkg string
|
||||||
calls []string
|
calls []string
|
||||||
}
|
}
|
||||||
|
@ -16,9 +17,9 @@ func (r *httpServeWithoutTimeouts) ID() string {
|
||||||
return r.MetaData.ID
|
return r.MetaData.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *httpServeWithoutTimeouts) Match(n ast.Node, c *gosec.Context) (gi *gosec.Issue, err error) {
|
func (r *httpServeWithoutTimeouts) Match(n ast.Node, c *gosec.Context) (gi *issue.Issue, err error) {
|
||||||
if _, matches := gosec.MatchCallByPackage(n, c, r.pkg, r.calls...); matches {
|
if _, matches := gosec.MatchCallByPackage(n, c, r.pkg, r.calls...); matches {
|
||||||
return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil
|
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
@ -28,11 +29,11 @@ func NewHTTPServeWithoutTimeouts(id string, conf gosec.Config) (gosec.Rule, []as
|
||||||
return &httpServeWithoutTimeouts{
|
return &httpServeWithoutTimeouts{
|
||||||
pkg: "net/http",
|
pkg: "net/http",
|
||||||
calls: []string{"ListenAndServe", "ListenAndServeTLS", "Serve", "ServeTLS"},
|
calls: []string{"ListenAndServe", "ListenAndServeTLS", "Serve", "ServeTLS"},
|
||||||
MetaData: gosec.MetaData{
|
MetaData: issue.MetaData{
|
||||||
ID: id,
|
ID: id,
|
||||||
What: "Use of net/http serve function that has no support for setting timeouts",
|
What: "Use of net/http serve function that has no support for setting timeouts",
|
||||||
Severity: gosec.Medium,
|
Severity: issue.Medium,
|
||||||
Confidence: gosec.High,
|
Confidence: issue.High,
|
||||||
},
|
},
|
||||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,11 @@ import (
|
||||||
"go/token"
|
"go/token"
|
||||||
|
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
)
|
)
|
||||||
|
|
||||||
type implicitAliasing struct {
|
type implicitAliasing struct {
|
||||||
gosec.MetaData
|
issue.MetaData
|
||||||
aliases map[*ast.Object]struct{}
|
aliases map[*ast.Object]struct{}
|
||||||
rightBrace token.Pos
|
rightBrace token.Pos
|
||||||
acceptableAlias []*ast.UnaryExpr
|
acceptableAlias []*ast.UnaryExpr
|
||||||
|
@ -27,7 +28,7 @@ func containsUnary(exprs []*ast.UnaryExpr, expr *ast.UnaryExpr) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *implicitAliasing) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
|
func (r *implicitAliasing) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
|
||||||
switch node := n.(type) {
|
switch node := n.(type) {
|
||||||
case *ast.RangeStmt:
|
case *ast.RangeStmt:
|
||||||
// When presented with a range statement, get the underlying Object bound to
|
// When presented with a range statement, get the underlying Object bound to
|
||||||
|
@ -73,7 +74,7 @@ func (r *implicitAliasing) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, er
|
||||||
// If we find a unary op of & (reference) of an object within r.aliases, complain.
|
// If we find a unary op of & (reference) of an object within r.aliases, complain.
|
||||||
if ident, ok := node.X.(*ast.Ident); ok && node.Op.String() == "&" {
|
if ident, ok := node.X.(*ast.Ident); ok && node.Op.String() == "&" {
|
||||||
if _, contains := r.aliases[ident.Obj]; contains {
|
if _, contains := r.aliases[ident.Obj]; contains {
|
||||||
return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil
|
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case *ast.ReturnStmt:
|
case *ast.ReturnStmt:
|
||||||
|
@ -94,10 +95,10 @@ func NewImplicitAliasing(id string, conf gosec.Config) (gosec.Rule, []ast.Node)
|
||||||
aliases: make(map[*ast.Object]struct{}),
|
aliases: make(map[*ast.Object]struct{}),
|
||||||
rightBrace: token.NoPos,
|
rightBrace: token.NoPos,
|
||||||
acceptableAlias: make([]*ast.UnaryExpr, 0),
|
acceptableAlias: make([]*ast.UnaryExpr, 0),
|
||||||
MetaData: gosec.MetaData{
|
MetaData: issue.MetaData{
|
||||||
ID: id,
|
ID: id,
|
||||||
Severity: gosec.Medium,
|
Severity: issue.Medium,
|
||||||
Confidence: gosec.Medium,
|
Confidence: issue.Medium,
|
||||||
What: "Implicit memory aliasing in for loop.",
|
What: "Implicit memory aliasing in for loop.",
|
||||||
},
|
},
|
||||||
}, []ast.Node{(*ast.RangeStmt)(nil), (*ast.UnaryExpr)(nil), (*ast.ReturnStmt)(nil)}
|
}, []ast.Node{(*ast.RangeStmt)(nil), (*ast.UnaryExpr)(nil), (*ast.ReturnStmt)(nil)}
|
||||||
|
|
|
@ -19,10 +19,11 @@ import (
|
||||||
"go/ast"
|
"go/ast"
|
||||||
|
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
)
|
)
|
||||||
|
|
||||||
type integerOverflowCheck struct {
|
type integerOverflowCheck struct {
|
||||||
gosec.MetaData
|
issue.MetaData
|
||||||
calls gosec.CallList
|
calls gosec.CallList
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +31,7 @@ func (i *integerOverflowCheck) ID() string {
|
||||||
return i.MetaData.ID
|
return i.MetaData.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *integerOverflowCheck) Match(node ast.Node, ctx *gosec.Context) (*gosec.Issue, error) {
|
func (i *integerOverflowCheck) Match(node ast.Node, ctx *gosec.Context) (*issue.Issue, error) {
|
||||||
var atoiVarObj map[*ast.Object]ast.Node
|
var atoiVarObj map[*ast.Object]ast.Node
|
||||||
|
|
||||||
// To check multiple lines, ctx.PassedValues is used to store temporary data.
|
// To check multiple lines, ctx.PassedValues is used to store temporary data.
|
||||||
|
@ -63,7 +64,7 @@ func (i *integerOverflowCheck) Match(node ast.Node, ctx *gosec.Context) (*gosec.
|
||||||
if idt, ok := n.Args[0].(*ast.Ident); ok {
|
if idt, ok := n.Args[0].(*ast.Ident); ok {
|
||||||
if _, ok := atoiVarObj[idt.Obj]; ok {
|
if _, ok := atoiVarObj[idt.Obj]; ok {
|
||||||
// Detect int32(v) and int16(v)
|
// Detect int32(v) and int16(v)
|
||||||
return gosec.NewIssue(ctx, n, i.ID(), i.What, i.Severity, i.Confidence), nil
|
return ctx.NewIssue(n, i.ID(), i.What, i.Severity, i.Confidence), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,10 +79,10 @@ func NewIntegerOverflowCheck(id string, conf gosec.Config) (gosec.Rule, []ast.No
|
||||||
calls := gosec.NewCallList()
|
calls := gosec.NewCallList()
|
||||||
calls.Add("strconv", "Atoi")
|
calls.Add("strconv", "Atoi")
|
||||||
return &integerOverflowCheck{
|
return &integerOverflowCheck{
|
||||||
MetaData: gosec.MetaData{
|
MetaData: issue.MetaData{
|
||||||
ID: id,
|
ID: id,
|
||||||
Severity: gosec.High,
|
Severity: issue.High,
|
||||||
Confidence: gosec.Medium,
|
Confidence: issue.Medium,
|
||||||
What: "Potential Integer overflow made by strconv.Atoi result conversion to int16/32",
|
What: "Potential Integer overflow made by strconv.Atoi result conversion to int16/32",
|
||||||
},
|
},
|
||||||
calls: calls,
|
calls: calls,
|
||||||
|
|
|
@ -4,10 +4,11 @@ import (
|
||||||
"go/ast"
|
"go/ast"
|
||||||
|
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
)
|
)
|
||||||
|
|
||||||
type usingOldMathBig struct {
|
type usingOldMathBig struct {
|
||||||
gosec.MetaData
|
issue.MetaData
|
||||||
calls gosec.CallList
|
calls gosec.CallList
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,18 +16,18 @@ func (r *usingOldMathBig) ID() string {
|
||||||
return r.MetaData.ID
|
return r.MetaData.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *usingOldMathBig) Match(node ast.Node, ctx *gosec.Context) (gi *gosec.Issue, err error) {
|
func (r *usingOldMathBig) Match(node ast.Node, ctx *gosec.Context) (gi *issue.Issue, err error) {
|
||||||
if callExpr := r.calls.ContainsPkgCallExpr(node, ctx, false); callExpr == nil {
|
if callExpr := r.calls.ContainsPkgCallExpr(node, ctx, false); callExpr == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
confidence := gosec.Low
|
confidence := issue.Low
|
||||||
major, minor, build := gosec.GoVersion()
|
major, minor, build := gosec.GoVersion()
|
||||||
if major == 1 && (minor == 16 && build < 14 || minor == 17 && build < 7) {
|
if major == 1 && (minor == 16 && build < 14 || minor == 17 && build < 7) {
|
||||||
confidence = gosec.Medium
|
confidence = issue.Medium
|
||||||
}
|
}
|
||||||
|
|
||||||
return gosec.NewIssue(ctx, node, r.ID(), r.What, r.Severity, confidence), nil
|
return ctx.NewIssue(node, r.ID(), r.What, r.Severity, confidence), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewUsingOldMathBig rule detects the use of Rat.SetString from math/big.
|
// NewUsingOldMathBig rule detects the use of Rat.SetString from math/big.
|
||||||
|
@ -35,10 +36,10 @@ func NewUsingOldMathBig(id string, _ gosec.Config) (gosec.Rule, []ast.Node) {
|
||||||
calls.Add("math/big.Rat", "SetString")
|
calls.Add("math/big.Rat", "SetString")
|
||||||
return &usingOldMathBig{
|
return &usingOldMathBig{
|
||||||
calls: calls,
|
calls: calls,
|
||||||
MetaData: gosec.MetaData{
|
MetaData: issue.MetaData{
|
||||||
ID: id,
|
ID: id,
|
||||||
What: "Potential uncontrolled memory consumption in Rat.SetString (CVE-2022-23772)",
|
What: "Potential uncontrolled memory consumption in Rat.SetString (CVE-2022-23772)",
|
||||||
Severity: gosec.High,
|
Severity: issue.High,
|
||||||
},
|
},
|
||||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,11 @@ import (
|
||||||
"go/ast"
|
"go/ast"
|
||||||
|
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
)
|
)
|
||||||
|
|
||||||
type pprofCheck struct {
|
type pprofCheck struct {
|
||||||
gosec.MetaData
|
issue.MetaData
|
||||||
importPath string
|
importPath string
|
||||||
importName string
|
importName string
|
||||||
}
|
}
|
||||||
|
@ -18,10 +19,10 @@ func (p *pprofCheck) ID() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Match checks for pprof imports
|
// Match checks for pprof imports
|
||||||
func (p *pprofCheck) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
|
func (p *pprofCheck) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
|
||||||
if node, ok := n.(*ast.ImportSpec); ok {
|
if node, ok := n.(*ast.ImportSpec); ok {
|
||||||
if p.importPath == unquote(node.Path.Value) && node.Name != nil && p.importName == node.Name.Name {
|
if p.importPath == unquote(node.Path.Value) && node.Name != nil && p.importName == node.Name.Name {
|
||||||
return gosec.NewIssue(c, node, p.ID(), p.What, p.Severity, p.Confidence), nil
|
return c.NewIssue(node, p.ID(), p.What, p.Severity, p.Confidence), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
@ -30,10 +31,10 @@ func (p *pprofCheck) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
|
||||||
// NewPprofCheck detects when the profiling endpoint is automatically exposed
|
// NewPprofCheck detects when the profiling endpoint is automatically exposed
|
||||||
func NewPprofCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
func NewPprofCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||||
return &pprofCheck{
|
return &pprofCheck{
|
||||||
MetaData: gosec.MetaData{
|
MetaData: issue.MetaData{
|
||||||
ID: id,
|
ID: id,
|
||||||
Severity: gosec.High,
|
Severity: issue.High,
|
||||||
Confidence: gosec.High,
|
Confidence: issue.High,
|
||||||
What: "Profiling endpoint is automatically exposed on /debug/pprof",
|
What: "Profiling endpoint is automatically exposed on /debug/pprof",
|
||||||
},
|
},
|
||||||
importPath: "net/http/pprof",
|
importPath: "net/http/pprof",
|
||||||
|
|
|
@ -18,10 +18,11 @@ import (
|
||||||
"go/ast"
|
"go/ast"
|
||||||
|
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
)
|
)
|
||||||
|
|
||||||
type weakRand struct {
|
type weakRand struct {
|
||||||
gosec.MetaData
|
issue.MetaData
|
||||||
funcNames []string
|
funcNames []string
|
||||||
packagePath string
|
packagePath string
|
||||||
}
|
}
|
||||||
|
@ -30,10 +31,10 @@ func (w *weakRand) ID() string {
|
||||||
return w.MetaData.ID
|
return w.MetaData.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *weakRand) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
|
func (w *weakRand) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
|
||||||
for _, funcName := range w.funcNames {
|
for _, funcName := range w.funcNames {
|
||||||
if _, matched := gosec.MatchCallByPackage(n, c, w.packagePath, funcName); matched {
|
if _, matched := gosec.MatchCallByPackage(n, c, w.packagePath, funcName); matched {
|
||||||
return gosec.NewIssue(c, n, w.ID(), w.What, w.Severity, w.Confidence), nil
|
return c.NewIssue(n, w.ID(), w.What, w.Severity, w.Confidence), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,10 +49,10 @@ func NewWeakRandCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||||
"Int31n", "Int63", "Int63n", "Intn", "NormalFloat64", "Uint32", "Uint64",
|
"Int31n", "Int63", "Int63n", "Intn", "NormalFloat64", "Uint32", "Uint64",
|
||||||
},
|
},
|
||||||
packagePath: "math/rand",
|
packagePath: "math/rand",
|
||||||
MetaData: gosec.MetaData{
|
MetaData: issue.MetaData{
|
||||||
ID: id,
|
ID: id,
|
||||||
Severity: gosec.High,
|
Severity: issue.High,
|
||||||
Confidence: gosec.Medium,
|
Confidence: issue.Medium,
|
||||||
What: "Use of weak random number generator (math/rand instead of crypto/rand)",
|
What: "Use of weak random number generator (math/rand instead of crypto/rand)",
|
||||||
},
|
},
|
||||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||||
|
|
|
@ -19,10 +19,11 @@ import (
|
||||||
"go/types"
|
"go/types"
|
||||||
|
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
)
|
)
|
||||||
|
|
||||||
type readfile struct {
|
type readfile struct {
|
||||||
gosec.MetaData
|
issue.MetaData
|
||||||
gosec.CallList
|
gosec.CallList
|
||||||
pathJoin gosec.CallList
|
pathJoin gosec.CallList
|
||||||
clean gosec.CallList
|
clean gosec.CallList
|
||||||
|
@ -86,7 +87,7 @@ func (r *readfile) trackFilepathClean(n ast.Node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Match inspects AST nodes to determine if the match the methods `os.Open` or `ioutil.ReadFile`
|
// Match inspects AST nodes to determine if the match the methods `os.Open` or `ioutil.ReadFile`
|
||||||
func (r *readfile) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
|
func (r *readfile) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
|
||||||
if node := r.clean.ContainsPkgCallExpr(n, c, false); node != nil {
|
if node := r.clean.ContainsPkgCallExpr(n, c, false); node != nil {
|
||||||
r.trackFilepathClean(n)
|
r.trackFilepathClean(n)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
@ -96,14 +97,14 @@ func (r *readfile) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
|
||||||
// eg. os.Open(filepath.Join("/tmp/", file))
|
// eg. os.Open(filepath.Join("/tmp/", file))
|
||||||
if callExpr, ok := arg.(*ast.CallExpr); ok {
|
if callExpr, ok := arg.(*ast.CallExpr); ok {
|
||||||
if r.isJoinFunc(callExpr, c) {
|
if r.isJoinFunc(callExpr, c) {
|
||||||
return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil
|
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// handles binary string concatenation eg. ioutil.Readfile("/tmp/" + file + "/blob")
|
// handles binary string concatenation eg. ioutil.Readfile("/tmp/" + file + "/blob")
|
||||||
if binExp, ok := arg.(*ast.BinaryExpr); ok {
|
if binExp, ok := arg.(*ast.BinaryExpr); ok {
|
||||||
// resolve all found identities from the BinaryExpr
|
// resolve all found identities from the BinaryExpr
|
||||||
if _, ok := gosec.FindVarIdentities(binExp, c); ok {
|
if _, ok := gosec.FindVarIdentities(binExp, c); ok {
|
||||||
return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil
|
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,7 +113,7 @@ func (r *readfile) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
|
||||||
if _, ok := obj.(*types.Var); ok &&
|
if _, ok := obj.(*types.Var); ok &&
|
||||||
!gosec.TryResolve(ident, c) &&
|
!gosec.TryResolve(ident, c) &&
|
||||||
!r.isFilepathClean(ident, c) {
|
!r.isFilepathClean(ident, c) {
|
||||||
return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil
|
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,11 +127,11 @@ func NewReadFile(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||||
pathJoin: gosec.NewCallList(),
|
pathJoin: gosec.NewCallList(),
|
||||||
clean: gosec.NewCallList(),
|
clean: gosec.NewCallList(),
|
||||||
CallList: gosec.NewCallList(),
|
CallList: gosec.NewCallList(),
|
||||||
MetaData: gosec.MetaData{
|
MetaData: issue.MetaData{
|
||||||
ID: id,
|
ID: id,
|
||||||
What: "Potential file inclusion via variable",
|
What: "Potential file inclusion via variable",
|
||||||
Severity: gosec.Medium,
|
Severity: issue.Medium,
|
||||||
Confidence: gosec.High,
|
Confidence: issue.High,
|
||||||
},
|
},
|
||||||
cleanedVar: map[any]ast.Node{},
|
cleanedVar: map[any]ast.Node{},
|
||||||
}
|
}
|
||||||
|
|
13
rules/rsa.go
13
rules/rsa.go
|
@ -19,10 +19,11 @@ import (
|
||||||
"go/ast"
|
"go/ast"
|
||||||
|
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
)
|
)
|
||||||
|
|
||||||
type weakKeyStrength struct {
|
type weakKeyStrength struct {
|
||||||
gosec.MetaData
|
issue.MetaData
|
||||||
calls gosec.CallList
|
calls gosec.CallList
|
||||||
bits int
|
bits int
|
||||||
}
|
}
|
||||||
|
@ -31,10 +32,10 @@ func (w *weakKeyStrength) ID() string {
|
||||||
return w.MetaData.ID
|
return w.MetaData.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *weakKeyStrength) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
|
func (w *weakKeyStrength) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
|
||||||
if callExpr := w.calls.ContainsPkgCallExpr(n, c, false); callExpr != nil {
|
if callExpr := w.calls.ContainsPkgCallExpr(n, c, false); callExpr != nil {
|
||||||
if bits, err := gosec.GetInt(callExpr.Args[1]); err == nil && bits < (int64)(w.bits) {
|
if bits, err := gosec.GetInt(callExpr.Args[1]); err == nil && bits < (int64)(w.bits) {
|
||||||
return gosec.NewIssue(c, n, w.ID(), w.What, w.Severity, w.Confidence), nil
|
return c.NewIssue(n, w.ID(), w.What, w.Severity, w.Confidence), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
@ -48,10 +49,10 @@ func NewWeakKeyStrength(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||||
return &weakKeyStrength{
|
return &weakKeyStrength{
|
||||||
calls: calls,
|
calls: calls,
|
||||||
bits: bits,
|
bits: bits,
|
||||||
MetaData: gosec.MetaData{
|
MetaData: issue.MetaData{
|
||||||
ID: id,
|
ID: id,
|
||||||
Severity: gosec.Medium,
|
Severity: issue.Medium,
|
||||||
Confidence: gosec.High,
|
Confidence: issue.High,
|
||||||
What: fmt.Sprintf("RSA keys should be at least %d bits", bits),
|
What: fmt.Sprintf("RSA keys should be at least %d bits", bits),
|
||||||
},
|
},
|
||||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||||
|
|
|
@ -18,10 +18,11 @@ import (
|
||||||
"go/ast"
|
"go/ast"
|
||||||
|
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
)
|
)
|
||||||
|
|
||||||
type slowloris struct {
|
type slowloris struct {
|
||||||
gosec.MetaData
|
issue.MetaData
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *slowloris) ID() string {
|
func (r *slowloris) ID() string {
|
||||||
|
@ -44,13 +45,13 @@ func containsReadHeaderTimeout(node *ast.CompositeLit) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *slowloris) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, error) {
|
func (r *slowloris) Match(n ast.Node, ctx *gosec.Context) (*issue.Issue, error) {
|
||||||
switch node := n.(type) {
|
switch node := n.(type) {
|
||||||
case *ast.CompositeLit:
|
case *ast.CompositeLit:
|
||||||
actualType := ctx.Info.TypeOf(node.Type)
|
actualType := ctx.Info.TypeOf(node.Type)
|
||||||
if actualType != nil && actualType.String() == "net/http.Server" {
|
if actualType != nil && actualType.String() == "net/http.Server" {
|
||||||
if !containsReadHeaderTimeout(node) {
|
if !containsReadHeaderTimeout(node) {
|
||||||
return gosec.NewIssue(ctx, node, r.ID(), r.What, r.Severity, r.Confidence), nil
|
return ctx.NewIssue(node, r.ID(), r.What, r.Severity, r.Confidence), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,11 +61,11 @@ func (r *slowloris) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, error)
|
||||||
// NewSlowloris attempts to find the http.Server struct and check if the ReadHeaderTimeout is configured.
|
// NewSlowloris attempts to find the http.Server struct and check if the ReadHeaderTimeout is configured.
|
||||||
func NewSlowloris(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
func NewSlowloris(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||||
return &slowloris{
|
return &slowloris{
|
||||||
MetaData: gosec.MetaData{
|
MetaData: issue.MetaData{
|
||||||
ID: id,
|
ID: id,
|
||||||
What: "Potential Slowloris Attack because ReadHeaderTimeout is not configured in the http.Server",
|
What: "Potential Slowloris Attack because ReadHeaderTimeout is not configured in the http.Server",
|
||||||
Confidence: gosec.Low,
|
Confidence: issue.Low,
|
||||||
Severity: gosec.Medium,
|
Severity: issue.Medium,
|
||||||
},
|
},
|
||||||
}, []ast.Node{(*ast.CompositeLit)(nil)}
|
}, []ast.Node{(*ast.CompositeLit)(nil)}
|
||||||
}
|
}
|
||||||
|
|
29
rules/sql.go
29
rules/sql.go
|
@ -20,10 +20,11 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
)
|
)
|
||||||
|
|
||||||
type sqlStatement struct {
|
type sqlStatement struct {
|
||||||
gosec.MetaData
|
issue.MetaData
|
||||||
gosec.CallList
|
gosec.CallList
|
||||||
|
|
||||||
// Contains a list of patterns which must all match for the rule to match.
|
// Contains a list of patterns which must all match for the rule to match.
|
||||||
|
@ -113,7 +114,7 @@ func (s *sqlStrConcat) checkObject(n *ast.Ident, c *gosec.Context) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkQuery verifies if the query parameters is a string concatenation
|
// checkQuery verifies if the query parameters is a string concatenation
|
||||||
func (s *sqlStrConcat) checkQuery(call *ast.CallExpr, ctx *gosec.Context) (*gosec.Issue, error) {
|
func (s *sqlStrConcat) checkQuery(call *ast.CallExpr, ctx *gosec.Context) (*issue.Issue, error) {
|
||||||
query, err := findQueryArg(call, ctx)
|
query, err := findQueryArg(call, ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -134,7 +135,7 @@ func (s *sqlStrConcat) checkQuery(call *ast.CallExpr, ctx *gosec.Context) (*gose
|
||||||
if op, ok := op.(*ast.Ident); ok && s.checkObject(op, ctx) {
|
if op, ok := op.(*ast.Ident); ok && s.checkObject(op, ctx) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return gosec.NewIssue(ctx, be, s.ID(), s.What, s.Severity, s.Confidence), nil
|
return ctx.NewIssue(be, s.ID(), s.What, s.Severity, s.Confidence), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -143,7 +144,7 @@ func (s *sqlStrConcat) checkQuery(call *ast.CallExpr, ctx *gosec.Context) (*gose
|
||||||
}
|
}
|
||||||
|
|
||||||
// Checks SQL query concatenation issues such as "SELECT * FROM table WHERE " + " ' OR 1=1"
|
// Checks SQL query concatenation issues such as "SELECT * FROM table WHERE " + " ' OR 1=1"
|
||||||
func (s *sqlStrConcat) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, error) {
|
func (s *sqlStrConcat) Match(n ast.Node, ctx *gosec.Context) (*issue.Issue, error) {
|
||||||
switch stmt := n.(type) {
|
switch stmt := n.(type) {
|
||||||
case *ast.AssignStmt:
|
case *ast.AssignStmt:
|
||||||
for _, expr := range stmt.Rhs {
|
for _, expr := range stmt.Rhs {
|
||||||
|
@ -166,10 +167,10 @@ func NewSQLStrConcat(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||||
patterns: []*regexp.Regexp{
|
patterns: []*regexp.Regexp{
|
||||||
regexp.MustCompile(`(?i)(SELECT|DELETE|INSERT|UPDATE|INTO|FROM|WHERE) `),
|
regexp.MustCompile(`(?i)(SELECT|DELETE|INSERT|UPDATE|INTO|FROM|WHERE) `),
|
||||||
},
|
},
|
||||||
MetaData: gosec.MetaData{
|
MetaData: issue.MetaData{
|
||||||
ID: id,
|
ID: id,
|
||||||
Severity: gosec.Medium,
|
Severity: issue.Medium,
|
||||||
Confidence: gosec.High,
|
Confidence: issue.High,
|
||||||
What: "SQL string concatenation",
|
What: "SQL string concatenation",
|
||||||
},
|
},
|
||||||
CallList: gosec.NewCallList(),
|
CallList: gosec.NewCallList(),
|
||||||
|
@ -212,7 +213,7 @@ func (s *sqlStrFormat) constObject(e ast.Expr, c *gosec.Context) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *sqlStrFormat) checkQuery(call *ast.CallExpr, ctx *gosec.Context) (*gosec.Issue, error) {
|
func (s *sqlStrFormat) checkQuery(call *ast.CallExpr, ctx *gosec.Context) (*issue.Issue, error) {
|
||||||
query, err := findQueryArg(call, ctx)
|
query, err := findQueryArg(call, ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -233,7 +234,7 @@ func (s *sqlStrFormat) checkQuery(call *ast.CallExpr, ctx *gosec.Context) (*gose
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *sqlStrFormat) checkFormatting(n ast.Node, ctx *gosec.Context) *gosec.Issue {
|
func (s *sqlStrFormat) checkFormatting(n ast.Node, ctx *gosec.Context) *issue.Issue {
|
||||||
// argIndex changes the function argument which gets matched to the regex
|
// argIndex changes the function argument which gets matched to the regex
|
||||||
argIndex := 0
|
argIndex := 0
|
||||||
if node := s.fmtCalls.ContainsPkgCallExpr(n, ctx, false); node != nil {
|
if node := s.fmtCalls.ContainsPkgCallExpr(n, ctx, false); node != nil {
|
||||||
|
@ -286,14 +287,14 @@ func (s *sqlStrFormat) checkFormatting(n ast.Node, ctx *gosec.Context) *gosec.Is
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if s.MatchPatterns(formatter) {
|
if s.MatchPatterns(formatter) {
|
||||||
return gosec.NewIssue(ctx, n, s.ID(), s.What, s.Severity, s.Confidence)
|
return ctx.NewIssue(n, s.ID(), s.What, s.Severity, s.Confidence)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check SQL query formatting issues such as "fmt.Sprintf("SELECT * FROM foo where '%s', userInput)"
|
// Check SQL query formatting issues such as "fmt.Sprintf("SELECT * FROM foo where '%s', userInput)"
|
||||||
func (s *sqlStrFormat) Match(n ast.Node, ctx *gosec.Context) (*gosec.Issue, error) {
|
func (s *sqlStrFormat) Match(n ast.Node, ctx *gosec.Context) (*issue.Issue, error) {
|
||||||
switch stmt := n.(type) {
|
switch stmt := n.(type) {
|
||||||
case *ast.AssignStmt:
|
case *ast.AssignStmt:
|
||||||
for _, expr := range stmt.Rhs {
|
for _, expr := range stmt.Rhs {
|
||||||
|
@ -334,10 +335,10 @@ func NewSQLStrFormat(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||||
regexp.MustCompile("(?i)(SELECT|DELETE|INSERT|UPDATE|INTO|FROM|WHERE)( |\n|\r|\t)"),
|
regexp.MustCompile("(?i)(SELECT|DELETE|INSERT|UPDATE|INTO|FROM|WHERE)( |\n|\r|\t)"),
|
||||||
regexp.MustCompile("%[^bdoxXfFp]"),
|
regexp.MustCompile("%[^bdoxXfFp]"),
|
||||||
},
|
},
|
||||||
MetaData: gosec.MetaData{
|
MetaData: issue.MetaData{
|
||||||
ID: id,
|
ID: id,
|
||||||
Severity: gosec.Medium,
|
Severity: issue.Medium,
|
||||||
Confidence: gosec.High,
|
Confidence: issue.High,
|
||||||
What: "SQL string formatting",
|
What: "SQL string formatting",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
13
rules/ssh.go
13
rules/ssh.go
|
@ -4,10 +4,11 @@ import (
|
||||||
"go/ast"
|
"go/ast"
|
||||||
|
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
)
|
)
|
||||||
|
|
||||||
type sshHostKey struct {
|
type sshHostKey struct {
|
||||||
gosec.MetaData
|
issue.MetaData
|
||||||
pkg string
|
pkg string
|
||||||
calls []string
|
calls []string
|
||||||
}
|
}
|
||||||
|
@ -16,9 +17,9 @@ func (r *sshHostKey) ID() string {
|
||||||
return r.MetaData.ID
|
return r.MetaData.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *sshHostKey) Match(n ast.Node, c *gosec.Context) (gi *gosec.Issue, err error) {
|
func (r *sshHostKey) Match(n ast.Node, c *gosec.Context) (gi *issue.Issue, err error) {
|
||||||
if _, matches := gosec.MatchCallByPackage(n, c, r.pkg, r.calls...); matches {
|
if _, matches := gosec.MatchCallByPackage(n, c, r.pkg, r.calls...); matches {
|
||||||
return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil
|
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
@ -28,11 +29,11 @@ func NewSSHHostKey(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||||
return &sshHostKey{
|
return &sshHostKey{
|
||||||
pkg: "golang.org/x/crypto/ssh",
|
pkg: "golang.org/x/crypto/ssh",
|
||||||
calls: []string{"InsecureIgnoreHostKey"},
|
calls: []string{"InsecureIgnoreHostKey"},
|
||||||
MetaData: gosec.MetaData{
|
MetaData: issue.MetaData{
|
||||||
ID: id,
|
ID: id,
|
||||||
What: "Use of ssh InsecureIgnoreHostKey should be audited",
|
What: "Use of ssh InsecureIgnoreHostKey should be audited",
|
||||||
Severity: gosec.Medium,
|
Severity: issue.Medium,
|
||||||
Confidence: gosec.High,
|
Confidence: issue.High,
|
||||||
},
|
},
|
||||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,10 +5,11 @@ import (
|
||||||
"go/types"
|
"go/types"
|
||||||
|
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ssrf struct {
|
type ssrf struct {
|
||||||
gosec.MetaData
|
issue.MetaData
|
||||||
gosec.CallList
|
gosec.CallList
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,11 +41,11 @@ func (r *ssrf) ResolveVar(n *ast.CallExpr, c *gosec.Context) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Match inspects AST nodes to determine if certain net/http methods are called with variable input
|
// Match inspects AST nodes to determine if certain net/http methods are called with variable input
|
||||||
func (r *ssrf) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
|
func (r *ssrf) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
|
||||||
// Call expression is using http package directly
|
// Call expression is using http package directly
|
||||||
if node := r.ContainsPkgCallExpr(n, c, false); node != nil {
|
if node := r.ContainsPkgCallExpr(n, c, false); node != nil {
|
||||||
if r.ResolveVar(node, c) {
|
if r.ResolveVar(node, c) {
|
||||||
return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil
|
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
@ -54,11 +55,11 @@ func (r *ssrf) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
|
||||||
func NewSSRFCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
func NewSSRFCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||||
rule := &ssrf{
|
rule := &ssrf{
|
||||||
CallList: gosec.NewCallList(),
|
CallList: gosec.NewCallList(),
|
||||||
MetaData: gosec.MetaData{
|
MetaData: issue.MetaData{
|
||||||
ID: id,
|
ID: id,
|
||||||
What: "Potential HTTP request made with variable url",
|
What: "Potential HTTP request made with variable url",
|
||||||
Severity: gosec.Medium,
|
Severity: issue.Medium,
|
||||||
Confidence: gosec.Medium,
|
Confidence: issue.Medium,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
rule.AddAll("net/http", "Do", "Get", "Head", "Post", "PostForm", "RoundTrip")
|
rule.AddAll("net/http", "Do", "Get", "Head", "Post", "PostForm", "RoundTrip")
|
||||||
|
|
|
@ -19,10 +19,11 @@ import (
|
||||||
"go/types"
|
"go/types"
|
||||||
|
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
)
|
)
|
||||||
|
|
||||||
type subprocess struct {
|
type subprocess struct {
|
||||||
gosec.MetaData
|
issue.MetaData
|
||||||
gosec.CallList
|
gosec.CallList
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +40,7 @@ func (r *subprocess) ID() string {
|
||||||
// is unsafe. For example:
|
// is unsafe. For example:
|
||||||
//
|
//
|
||||||
// syscall.Exec("echo", "foobar" + tainted)
|
// syscall.Exec("echo", "foobar" + tainted)
|
||||||
func (r *subprocess) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
|
func (r *subprocess) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
|
||||||
if node := r.ContainsPkgCallExpr(n, c, false); node != nil {
|
if node := r.ContainsPkgCallExpr(n, c, false); node != nil {
|
||||||
args := node.Args
|
args := node.Args
|
||||||
if r.isContext(n, c) {
|
if r.isContext(n, c) {
|
||||||
|
@ -64,7 +65,7 @@ func (r *subprocess) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
|
||||||
_, assignment := ident.Obj.Decl.(*ast.AssignStmt)
|
_, assignment := ident.Obj.Decl.(*ast.AssignStmt)
|
||||||
if variable && assignment {
|
if variable && assignment {
|
||||||
if !gosec.TryResolve(ident, c) {
|
if !gosec.TryResolve(ident, c) {
|
||||||
return gosec.NewIssue(c, n, r.ID(), "Subprocess launched with variable", gosec.Medium, gosec.High), nil
|
return c.NewIssue(n, r.ID(), "Subprocess launched with variable", issue.Medium, issue.High), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case *ast.Field:
|
case *ast.Field:
|
||||||
|
@ -74,21 +75,21 @@ func (r *subprocess) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
|
||||||
vv, vvok := obj.(*types.Var)
|
vv, vvok := obj.(*types.Var)
|
||||||
|
|
||||||
if vvok && vv.Parent().Lookup(ident.Name) == nil {
|
if vvok && vv.Parent().Lookup(ident.Name) == nil {
|
||||||
return gosec.NewIssue(c, n, r.ID(), "Subprocess launched with variable", gosec.Medium, gosec.High), nil
|
return c.NewIssue(n, r.ID(), "Subprocess launched with variable", issue.Medium, issue.High), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case *ast.ValueSpec:
|
case *ast.ValueSpec:
|
||||||
_, valueSpec := ident.Obj.Decl.(*ast.ValueSpec)
|
_, valueSpec := ident.Obj.Decl.(*ast.ValueSpec)
|
||||||
if variable && valueSpec {
|
if variable && valueSpec {
|
||||||
if !gosec.TryResolve(ident, c) {
|
if !gosec.TryResolve(ident, c) {
|
||||||
return gosec.NewIssue(c, n, r.ID(), "Subprocess launched with variable", gosec.Medium, gosec.High), nil
|
return c.NewIssue(n, r.ID(), "Subprocess launched with variable", issue.Medium, issue.High), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if !gosec.TryResolve(arg, c) {
|
} else if !gosec.TryResolve(arg, c) {
|
||||||
// the arg is not a constant or a variable but instead a function call or os.Args[i]
|
// the arg is not a constant or a variable but instead a function call or os.Args[i]
|
||||||
return gosec.NewIssue(c, n, r.ID(), "Subprocess launched with a potential tainted input or cmd arguments", gosec.Medium, gosec.High), nil
|
return c.NewIssue(n, r.ID(), "Subprocess launched with a potential tainted input or cmd arguments", issue.Medium, issue.High), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -110,7 +111,7 @@ func (r *subprocess) isContext(n ast.Node, ctx *gosec.Context) bool {
|
||||||
|
|
||||||
// NewSubproc detects cases where we are forking out to an external process
|
// NewSubproc detects cases where we are forking out to an external process
|
||||||
func NewSubproc(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
func NewSubproc(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||||
rule := &subprocess{gosec.MetaData{ID: id}, gosec.NewCallList()}
|
rule := &subprocess{issue.MetaData{ID: id}, gosec.NewCallList()}
|
||||||
rule.Add("os/exec", "Command")
|
rule.Add("os/exec", "Command")
|
||||||
rule.Add("os/exec", "CommandContext")
|
rule.Add("os/exec", "CommandContext")
|
||||||
rule.Add("syscall", "Exec")
|
rule.Add("syscall", "Exec")
|
||||||
|
|
|
@ -19,10 +19,11 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
)
|
)
|
||||||
|
|
||||||
type badTempFile struct {
|
type badTempFile struct {
|
||||||
gosec.MetaData
|
issue.MetaData
|
||||||
calls gosec.CallList
|
calls gosec.CallList
|
||||||
args *regexp.Regexp
|
args *regexp.Regexp
|
||||||
argCalls gosec.CallList
|
argCalls gosec.CallList
|
||||||
|
@ -33,15 +34,15 @@ func (t *badTempFile) ID() string {
|
||||||
return t.MetaData.ID
|
return t.MetaData.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *badTempFile) findTempDirArgs(n ast.Node, c *gosec.Context, suspect ast.Node) *gosec.Issue {
|
func (t *badTempFile) findTempDirArgs(n ast.Node, c *gosec.Context, suspect ast.Node) *issue.Issue {
|
||||||
if s, e := gosec.GetString(suspect); e == nil {
|
if s, e := gosec.GetString(suspect); e == nil {
|
||||||
if t.args.MatchString(s) {
|
if t.args.MatchString(s) {
|
||||||
return gosec.NewIssue(c, n, t.ID(), t.What, t.Severity, t.Confidence)
|
return c.NewIssue(n, t.ID(), t.What, t.Severity, t.Confidence)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if ce := t.argCalls.ContainsPkgCallExpr(suspect, c, false); ce != nil {
|
if ce := t.argCalls.ContainsPkgCallExpr(suspect, c, false); ce != nil {
|
||||||
return gosec.NewIssue(c, n, t.ID(), t.What, t.Severity, t.Confidence)
|
return c.NewIssue(n, t.ID(), t.What, t.Severity, t.Confidence)
|
||||||
}
|
}
|
||||||
if be, ok := suspect.(*ast.BinaryExpr); ok {
|
if be, ok := suspect.(*ast.BinaryExpr); ok {
|
||||||
if ops := gosec.GetBinaryExprOperands(be); len(ops) != 0 {
|
if ops := gosec.GetBinaryExprOperands(be); len(ops) != 0 {
|
||||||
|
@ -55,7 +56,7 @@ func (t *badTempFile) findTempDirArgs(n ast.Node, c *gosec.Context, suspect ast.
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *badTempFile) Match(n ast.Node, c *gosec.Context) (gi *gosec.Issue, err error) {
|
func (t *badTempFile) Match(n ast.Node, c *gosec.Context) (gi *issue.Issue, err error) {
|
||||||
if node := t.calls.ContainsPkgCallExpr(n, c, false); node != nil {
|
if node := t.calls.ContainsPkgCallExpr(n, c, false); node != nil {
|
||||||
return t.findTempDirArgs(n, c, node.Args[0]), nil
|
return t.findTempDirArgs(n, c, node.Args[0]), nil
|
||||||
}
|
}
|
||||||
|
@ -77,10 +78,10 @@ func NewBadTempFile(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||||
args: regexp.MustCompile(`^(/(usr|var))?/tmp(/.*)?$`),
|
args: regexp.MustCompile(`^(/(usr|var))?/tmp(/.*)?$`),
|
||||||
argCalls: argCalls,
|
argCalls: argCalls,
|
||||||
nestedCalls: nestedCalls,
|
nestedCalls: nestedCalls,
|
||||||
MetaData: gosec.MetaData{
|
MetaData: issue.MetaData{
|
||||||
ID: id,
|
ID: id,
|
||||||
Severity: gosec.Medium,
|
Severity: issue.Medium,
|
||||||
Confidence: gosec.High,
|
Confidence: issue.High,
|
||||||
What: "File creation in shared tmp directory without using ioutil.Tempfile",
|
What: "File creation in shared tmp directory without using ioutil.Tempfile",
|
||||||
},
|
},
|
||||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||||
|
|
|
@ -18,10 +18,11 @@ import (
|
||||||
"go/ast"
|
"go/ast"
|
||||||
|
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
)
|
)
|
||||||
|
|
||||||
type templateCheck struct {
|
type templateCheck struct {
|
||||||
gosec.MetaData
|
issue.MetaData
|
||||||
calls gosec.CallList
|
calls gosec.CallList
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,11 +30,11 @@ func (t *templateCheck) ID() string {
|
||||||
return t.MetaData.ID
|
return t.MetaData.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *templateCheck) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
|
func (t *templateCheck) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
|
||||||
if node := t.calls.ContainsPkgCallExpr(n, c, false); node != nil {
|
if node := t.calls.ContainsPkgCallExpr(n, c, false); node != nil {
|
||||||
for _, arg := range node.Args {
|
for _, arg := range node.Args {
|
||||||
if _, ok := arg.(*ast.BasicLit); !ok { // basic lits are safe
|
if _, ok := arg.(*ast.BasicLit); !ok { // basic lits are safe
|
||||||
return gosec.NewIssue(c, n, t.ID(), t.What, t.Severity, t.Confidence), nil
|
return c.NewIssue(n, t.ID(), t.What, t.Severity, t.Confidence), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,10 +51,10 @@ func NewTemplateCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||||
calls.Add("html/template", "URL")
|
calls.Add("html/template", "URL")
|
||||||
return &templateCheck{
|
return &templateCheck{
|
||||||
calls: calls,
|
calls: calls,
|
||||||
MetaData: gosec.MetaData{
|
MetaData: issue.MetaData{
|
||||||
ID: id,
|
ID: id,
|
||||||
Severity: gosec.Medium,
|
Severity: issue.Medium,
|
||||||
Confidence: gosec.Low,
|
Confidence: issue.Low,
|
||||||
What: "The used method does not auto-escape HTML. This can potentially lead to 'Cross-site Scripting' vulnerabilities, in case the attacker controls the input.",
|
What: "The used method does not auto-escape HTML. This can potentially lead to 'Cross-site Scripting' vulnerabilities, in case the attacker controls the input.",
|
||||||
},
|
},
|
||||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||||
|
|
27
rules/tls.go
27
rules/tls.go
|
@ -24,10 +24,11 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
)
|
)
|
||||||
|
|
||||||
type insecureConfigTLS struct {
|
type insecureConfigTLS struct {
|
||||||
gosec.MetaData
|
issue.MetaData
|
||||||
MinVersion int64
|
MinVersion int64
|
||||||
MaxVersion int64
|
MaxVersion int64
|
||||||
requiredType string
|
requiredType string
|
||||||
|
@ -49,13 +50,13 @@ func stringInSlice(a string, list []string) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *insecureConfigTLS) processTLSCipherSuites(n ast.Node, c *gosec.Context) *gosec.Issue {
|
func (t *insecureConfigTLS) processTLSCipherSuites(n ast.Node, c *gosec.Context) *issue.Issue {
|
||||||
if ciphers, ok := n.(*ast.CompositeLit); ok {
|
if ciphers, ok := n.(*ast.CompositeLit); ok {
|
||||||
for _, cipher := range ciphers.Elts {
|
for _, cipher := range ciphers.Elts {
|
||||||
if ident, ok := cipher.(*ast.SelectorExpr); ok {
|
if ident, ok := cipher.(*ast.SelectorExpr); ok {
|
||||||
if !stringInSlice(ident.Sel.Name, t.goodCiphers) {
|
if !stringInSlice(ident.Sel.Name, t.goodCiphers) {
|
||||||
err := fmt.Sprintf("TLS Bad Cipher Suite: %s", ident.Sel.Name)
|
err := fmt.Sprintf("TLS Bad Cipher Suite: %s", ident.Sel.Name)
|
||||||
return gosec.NewIssue(c, ident, t.ID(), err, gosec.High, gosec.High)
|
return c.NewIssue(ident, t.ID(), err, issue.High, issue.High)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,7 +64,7 @@ func (t *insecureConfigTLS) processTLSCipherSuites(n ast.Node, c *gosec.Context)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *insecureConfigTLS) processTLSConf(n ast.Node, c *gosec.Context) *gosec.Issue {
|
func (t *insecureConfigTLS) processTLSConf(n ast.Node, c *gosec.Context) *issue.Issue {
|
||||||
if kve, ok := n.(*ast.KeyValueExpr); ok {
|
if kve, ok := n.(*ast.KeyValueExpr); ok {
|
||||||
issue := t.processTLSConfVal(kve.Key, kve.Value, c)
|
issue := t.processTLSConfVal(kve.Key, kve.Value, c)
|
||||||
if issue != nil {
|
if issue != nil {
|
||||||
|
@ -83,27 +84,27 @@ func (t *insecureConfigTLS) processTLSConf(n ast.Node, c *gosec.Context) *gosec.
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *insecureConfigTLS) processTLSConfVal(key ast.Expr, value ast.Expr, c *gosec.Context) *gosec.Issue {
|
func (t *insecureConfigTLS) processTLSConfVal(key ast.Expr, value ast.Expr, c *gosec.Context) *issue.Issue {
|
||||||
if ident, ok := key.(*ast.Ident); ok {
|
if ident, ok := key.(*ast.Ident); ok {
|
||||||
switch ident.Name {
|
switch ident.Name {
|
||||||
case "InsecureSkipVerify":
|
case "InsecureSkipVerify":
|
||||||
if node, ok := value.(*ast.Ident); ok {
|
if node, ok := value.(*ast.Ident); ok {
|
||||||
if node.Name != "false" {
|
if node.Name != "false" {
|
||||||
return gosec.NewIssue(c, value, t.ID(), "TLS InsecureSkipVerify set true.", gosec.High, gosec.High)
|
return c.NewIssue(value, t.ID(), "TLS InsecureSkipVerify set true.", issue.High, issue.High)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// TODO(tk): symbol tab look up to get the actual value
|
// TODO(tk): symbol tab look up to get the actual value
|
||||||
return gosec.NewIssue(c, value, t.ID(), "TLS InsecureSkipVerify may be true.", gosec.High, gosec.Low)
|
return c.NewIssue(value, t.ID(), "TLS InsecureSkipVerify may be true.", issue.High, issue.Low)
|
||||||
}
|
}
|
||||||
|
|
||||||
case "PreferServerCipherSuites":
|
case "PreferServerCipherSuites":
|
||||||
if node, ok := value.(*ast.Ident); ok {
|
if node, ok := value.(*ast.Ident); ok {
|
||||||
if node.Name == "false" {
|
if node.Name == "false" {
|
||||||
return gosec.NewIssue(c, value, t.ID(), "TLS PreferServerCipherSuites set false.", gosec.Medium, gosec.High)
|
return c.NewIssue(value, t.ID(), "TLS PreferServerCipherSuites set false.", issue.Medium, issue.High)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// TODO(tk): symbol tab look up to get the actual value
|
// TODO(tk): symbol tab look up to get the actual value
|
||||||
return gosec.NewIssue(c, value, t.ID(), "TLS PreferServerCipherSuites may be false.", gosec.Medium, gosec.Low)
|
return c.NewIssue(value, t.ID(), "TLS PreferServerCipherSuites may be false.", issue.Medium, issue.Low)
|
||||||
}
|
}
|
||||||
|
|
||||||
case "MinVersion":
|
case "MinVersion":
|
||||||
|
@ -188,16 +189,16 @@ func (t *insecureConfigTLS) mapVersion(version string) int64 {
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *insecureConfigTLS) checkVersion(n ast.Node, c *gosec.Context) *gosec.Issue {
|
func (t *insecureConfigTLS) checkVersion(n ast.Node, c *gosec.Context) *issue.Issue {
|
||||||
if t.actualMaxVersion == 0 && t.actualMinVersion >= t.MinVersion {
|
if t.actualMaxVersion == 0 && t.actualMinVersion >= t.MinVersion {
|
||||||
// no warning is generated since the min version is greater than the secure min version
|
// no warning is generated since the min version is greater than the secure min version
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if t.actualMinVersion < t.MinVersion {
|
if t.actualMinVersion < t.MinVersion {
|
||||||
return gosec.NewIssue(c, n, t.ID(), "TLS MinVersion too low.", gosec.High, gosec.High)
|
return c.NewIssue(n, t.ID(), "TLS MinVersion too low.", issue.High, issue.High)
|
||||||
}
|
}
|
||||||
if t.actualMaxVersion < t.MaxVersion {
|
if t.actualMaxVersion < t.MaxVersion {
|
||||||
return gosec.NewIssue(c, n, t.ID(), "TLS MaxVersion too low.", gosec.High, gosec.High)
|
return c.NewIssue(n, t.ID(), "TLS MaxVersion too low.", issue.High, issue.High)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -207,7 +208,7 @@ func (t *insecureConfigTLS) resetVersion() {
|
||||||
t.actualMinVersion = 0
|
t.actualMinVersion = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *insecureConfigTLS) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
|
func (t *insecureConfigTLS) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
|
||||||
if complit, ok := n.(*ast.CompositeLit); ok && complit.Type != nil {
|
if complit, ok := n.(*ast.CompositeLit); ok && complit.Type != nil {
|
||||||
actualType := c.Info.TypeOf(complit.Type)
|
actualType := c.Info.TypeOf(complit.Type)
|
||||||
if actualType != nil && actualType.String() == t.requiredType {
|
if actualType != nil && actualType.String() == t.requiredType {
|
||||||
|
|
|
@ -4,13 +4,14 @@ import (
|
||||||
"go/ast"
|
"go/ast"
|
||||||
|
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewModernTLSCheck creates a check for Modern TLS ciphers
|
// NewModernTLSCheck creates a check for Modern TLS ciphers
|
||||||
// DO NOT EDIT - generated by tlsconfig tool
|
// DO NOT EDIT - generated by tlsconfig tool
|
||||||
func NewModernTLSCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
func NewModernTLSCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||||
return &insecureConfigTLS{
|
return &insecureConfigTLS{
|
||||||
MetaData: gosec.MetaData{ID: id},
|
MetaData: issue.MetaData{ID: id},
|
||||||
requiredType: "crypto/tls.Config",
|
requiredType: "crypto/tls.Config",
|
||||||
MinVersion: 0x0304,
|
MinVersion: 0x0304,
|
||||||
MaxVersion: 0x0304,
|
MaxVersion: 0x0304,
|
||||||
|
@ -26,7 +27,7 @@ func NewModernTLSCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||||
// DO NOT EDIT - generated by tlsconfig tool
|
// DO NOT EDIT - generated by tlsconfig tool
|
||||||
func NewIntermediateTLSCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
func NewIntermediateTLSCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||||
return &insecureConfigTLS{
|
return &insecureConfigTLS{
|
||||||
MetaData: gosec.MetaData{ID: id},
|
MetaData: issue.MetaData{ID: id},
|
||||||
requiredType: "crypto/tls.Config",
|
requiredType: "crypto/tls.Config",
|
||||||
MinVersion: 0x0303,
|
MinVersion: 0x0303,
|
||||||
MaxVersion: 0x0304,
|
MaxVersion: 0x0304,
|
||||||
|
@ -52,7 +53,7 @@ func NewIntermediateTLSCheck(id string, conf gosec.Config) (gosec.Rule, []ast.No
|
||||||
// DO NOT EDIT - generated by tlsconfig tool
|
// DO NOT EDIT - generated by tlsconfig tool
|
||||||
func NewOldTLSCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
func NewOldTLSCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||||
return &insecureConfigTLS{
|
return &insecureConfigTLS{
|
||||||
MetaData: gosec.MetaData{ID: id},
|
MetaData: issue.MetaData{ID: id},
|
||||||
requiredType: "crypto/tls.Config",
|
requiredType: "crypto/tls.Config",
|
||||||
MinVersion: 0x0301,
|
MinVersion: 0x0301,
|
||||||
MaxVersion: 0x0304,
|
MaxVersion: 0x0304,
|
||||||
|
|
|
@ -18,10 +18,11 @@ import (
|
||||||
"go/ast"
|
"go/ast"
|
||||||
|
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
)
|
)
|
||||||
|
|
||||||
type usingUnsafe struct {
|
type usingUnsafe struct {
|
||||||
gosec.MetaData
|
issue.MetaData
|
||||||
pkg string
|
pkg string
|
||||||
calls []string
|
calls []string
|
||||||
}
|
}
|
||||||
|
@ -30,9 +31,9 @@ func (r *usingUnsafe) ID() string {
|
||||||
return r.MetaData.ID
|
return r.MetaData.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *usingUnsafe) Match(n ast.Node, c *gosec.Context) (gi *gosec.Issue, err error) {
|
func (r *usingUnsafe) Match(n ast.Node, c *gosec.Context) (gi *issue.Issue, err error) {
|
||||||
if _, matches := gosec.MatchCallByPackage(n, c, r.pkg, r.calls...); matches {
|
if _, matches := gosec.MatchCallByPackage(n, c, r.pkg, r.calls...); matches {
|
||||||
return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil
|
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
@ -43,11 +44,11 @@ func NewUsingUnsafe(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
|
||||||
return &usingUnsafe{
|
return &usingUnsafe{
|
||||||
pkg: "unsafe",
|
pkg: "unsafe",
|
||||||
calls: []string{"Alignof", "Offsetof", "Sizeof", "Pointer"},
|
calls: []string{"Alignof", "Offsetof", "Sizeof", "Pointer"},
|
||||||
MetaData: gosec.MetaData{
|
MetaData: issue.MetaData{
|
||||||
ID: id,
|
ID: id,
|
||||||
What: "Use of unsafe calls should be audited",
|
What: "Use of unsafe calls should be audited",
|
||||||
Severity: gosec.Low,
|
Severity: issue.Low,
|
||||||
Confidence: gosec.High,
|
Confidence: issue.High,
|
||||||
},
|
},
|
||||||
}, []ast.Node{(*ast.CallExpr)(nil)}
|
}, []ast.Node{(*ast.CallExpr)(nil)}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,10 +18,11 @@ import (
|
||||||
"go/ast"
|
"go/ast"
|
||||||
|
|
||||||
"github.com/securego/gosec/v2"
|
"github.com/securego/gosec/v2"
|
||||||
|
"github.com/securego/gosec/v2/issue"
|
||||||
)
|
)
|
||||||
|
|
||||||
type usesWeakCryptography struct {
|
type usesWeakCryptography struct {
|
||||||
gosec.MetaData
|
issue.MetaData
|
||||||
blocklist map[string][]string
|
blocklist map[string][]string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,10 +30,10 @@ func (r *usesWeakCryptography) ID() string {
|
||||||
return r.MetaData.ID
|
return r.MetaData.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *usesWeakCryptography) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) {
|
func (r *usesWeakCryptography) Match(n ast.Node, c *gosec.Context) (*issue.Issue, error) {
|
||||||
for pkg, funcs := range r.blocklist {
|
for pkg, funcs := range r.blocklist {
|
||||||
if _, matched := gosec.MatchCallByPackage(n, c, pkg, funcs...); matched {
|
if _, matched := gosec.MatchCallByPackage(n, c, pkg, funcs...); matched {
|
||||||
return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil
|
return c.NewIssue(n, r.ID(), r.What, r.Severity, r.Confidence), nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
@ -47,10 +48,10 @@ func NewUsesWeakCryptography(id string, conf gosec.Config) (gosec.Rule, []ast.No
|
||||||
calls["crypto/rc4"] = []string{"NewCipher"}
|
calls["crypto/rc4"] = []string{"NewCipher"}
|
||||||
rule := &usesWeakCryptography{
|
rule := &usesWeakCryptography{
|
||||||
blocklist: calls,
|
blocklist: calls,
|
||||||
MetaData: gosec.MetaData{
|
MetaData: issue.MetaData{
|
||||||
ID: id,
|
ID: id,
|
||||||
Severity: gosec.Medium,
|
Severity: issue.Medium,
|
||||||
Confidence: gosec.High,
|
Confidence: issue.High,
|
||||||
What: "Use of weak cryptographic primitive",
|
What: "Use of weak cryptographic primitive",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue