gopkg.in/alecthomas/gometalinter.v3@v3.0.0/_linters/src/github.com/securego/gosec/rules/ssrf.go (about) 1 package rules 2 3 import ( 4 "go/ast" 5 "go/types" 6 7 "github.com/securego/gosec" 8 ) 9 10 type ssrf struct { 11 gosec.MetaData 12 gosec.CallList 13 } 14 15 // ID returns the identifier for this rule 16 func (r *ssrf) ID() string { 17 return r.MetaData.ID 18 } 19 20 // ResolveVar tries to resolve the first argument of a call expression 21 // The first argument is the url 22 func (r *ssrf) ResolveVar(n *ast.CallExpr, c *gosec.Context) bool { 23 if len(n.Args) > 0 { 24 arg := n.Args[0] 25 if ident, ok := arg.(*ast.Ident); ok { 26 obj := c.Info.ObjectOf(ident) 27 if _, ok := obj.(*types.Var); ok && !gosec.TryResolve(ident, c) { 28 return true 29 } 30 } 31 } 32 return false 33 } 34 35 // Match inspects AST nodes to determine if certain net/http methods are called with variable input 36 func (r *ssrf) Match(n ast.Node, c *gosec.Context) (*gosec.Issue, error) { 37 // Call expression is using http package directly 38 if node := r.ContainsCallExpr(n, c); node != nil { 39 if r.ResolveVar(node, c) { 40 return gosec.NewIssue(c, n, r.ID(), r.What, r.Severity, r.Confidence), nil 41 } 42 } 43 return nil, nil 44 } 45 46 // NewSSRFCheck detects cases where HTTP requests are sent 47 func NewSSRFCheck(id string, conf gosec.Config) (gosec.Rule, []ast.Node) { 48 rule := &ssrf{ 49 CallList: gosec.NewCallList(), 50 MetaData: gosec.MetaData{ 51 ID: id, 52 What: "Potential HTTP request made with variable url", 53 Severity: gosec.Medium, 54 Confidence: gosec.Medium, 55 }, 56 } 57 rule.AddAll("net/http", "Do", "Get", "Head", "Post", "PostForm", "RoundTrip") 58 return rule, []ast.Node{(*ast.CallExpr)(nil)} 59 }