From 9cee24cccd863ecc5786933bfec615e6a158e99f Mon Sep 17 00:00:00 2001 From: Cosmin Cojocar Date: Fri, 20 Sep 2019 10:46:06 +0200 Subject: [PATCH] Add a rule which detects when pprof endpoint is automatically exposed Signed-off-by: Cosmin Cojocar --- rules/pprof.go | 42 ++++++++++++++++++++++++++++++++++++++++++ rules/rulelist.go | 1 + rules/rules_test.go | 4 ++++ testutils/source.go | 17 +++++++++++++++++ 4 files changed, 64 insertions(+) create mode 100644 rules/pprof.go diff --git a/rules/pprof.go b/rules/pprof.go new file mode 100644 index 0000000..cb2f462 --- /dev/null +++ b/rules/pprof.go @@ -0,0 +1,42 @@ +package rules + +import ( + "go/ast" + + "github.com/securego/gosec" +) + +type pprofCheck struct { + gosec.MetaData + importPath string + importName string +} + +// ID returns the ID of the check +func (p *pprofCheck) ID() string { + return p.MetaData.ID +} + +// Match checks for pprof imports +func (p *pprofCheck) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) { + if node, ok := n.(*ast.ImportSpec); ok { + if p.importPath == unquote(node.Path.Value) && p.importName == node.Name.Name { + return gosec.NewIssue(c, node, p.ID(), p.What, p.Severity, p.Confidence), nil + } + } + return nil, nil +} + +// NewPprofCheck detects when the profiling endpoint is automatically exposed +func NewPprofCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { + return &pprofCheck{ + MetaData: gosec.MetaData{ + ID: id, + Severity: gosec.High, + Confidence: gosec.High, + What: "Profiling endpoint is automatically exposed on /debug/pprof", + }, + importPath: "net/http/pprof", + importName: "_", + }, []ast.Node{(*ast.ImportSpec)(nil)} +} diff --git a/rules/rulelist.go b/rules/rulelist.go index b8a28a8..97d262a 100644 --- a/rules/rulelist.go +++ b/rules/rulelist.go @@ -65,6 +65,7 @@ func Generate(filters ...RuleFilter) RuleList { {"G104", "Audit errors not checked", NewNoErrorCheck}, {"G106", "Audit the use of ssh.InsecureIgnoreHostKey function", NewSSHHostKey}, {"G107", "Url provided to HTTP request as taint input", NewSSRFCheck}, + {"G108", "Profiling endpoint is automatically exposed", NewPprofCheck}, // injection {"G201", "SQL query construction using format string", NewSQLStrFormat}, diff --git a/rules/rules_test.go b/rules/rules_test.go index 98e122c..4efdfbe 100644 --- a/rules/rules_test.go +++ b/rules/rules_test.go @@ -79,6 +79,10 @@ var _ = Describe("gosec rules", func() { runner("G107", testutils.SampleCodeG107) }) + It("should detect pprof endpoint", func() { + runner("G108", testutils.SampleCodeG108) + }) + It("should detect sql injection via format strings", func() { runner("G201", testutils.SampleCodeG201) }) diff --git a/testutils/source.go b/testutils/source.go index 964f8ca..04b60fa 100644 --- a/testutils/source.go +++ b/testutils/source.go @@ -404,6 +404,23 @@ func main() { } fmt.Println(resp.Status) }`}, 0, gosec.NewConfig()}} + // SampleCodeG108 - pprof endpoint automatically exposed + SampleCodeG108 = []CodeSample{{[]string{` +package main + +import ( + "fmt" + "log" + "net/http" + _ "net/http/pprof" +) + +func main() { + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "Hello World!") + }) + log.Fatal(http.ListenAndServe(":8080", nil)) +}`}, 1, gosec.NewConfig()}} // SampleCodeG201 - SQL injection via format string SampleCodeG201 = []CodeSample{ {[]string{`