feat(rules): add support for detecting high entropy strings in composite literals (#1447)

This commit is contained in:
oittaa
2026-01-02 08:58:08 +01:00
committed by GitHub
parent 082deb6cee
commit 717706e815
2 changed files with 176 additions and 2 deletions

View File

@@ -229,6 +229,8 @@ func (r *credentials) Match(n ast.Node, ctx *gosec.Context) (*issue.Issue, error
return r.matchValueSpec(node, ctx)
case *ast.BinaryExpr:
return r.matchEqualityCheck(node, ctx)
case *ast.CompositeLit:
return r.matchCompositeLit(node, ctx)
}
return nil, nil
}
@@ -334,6 +336,44 @@ func (r *credentials) matchEqualityCheck(binaryExpr *ast.BinaryExpr, ctx *gosec.
return nil, nil
}
func (r *credentials) matchCompositeLit(lit *ast.CompositeLit, ctx *gosec.Context) (*issue.Issue, error) {
for _, elt := range lit.Elts {
if kv, ok := elt.(*ast.KeyValueExpr); ok {
// Check if the key matches the credential pattern (struct field name or map string literal key)
matchedKey := false
if ident, ok := kv.Key.(*ast.Ident); ok {
if r.pattern.MatchString(ident.Name) {
matchedKey = true
}
}
if keyStr, err := gosec.GetString(kv.Key); err == nil {
if r.pattern.MatchString(keyStr) {
matchedKey = true
}
}
// If key matches, check value for high entropy (generic credential warning)
if matchedKey {
if val, err := gosec.GetString(kv.Value); err == nil {
if r.ignoreEntropy || r.isHighEntropyString(val) {
return ctx.NewIssue(lit, r.ID(), r.What, r.Severity, r.Confidence), nil
}
}
}
// Separately check value for specific secret patterns (regardless of key)
if val, err := gosec.GetString(kv.Value); err == nil {
if r.ignoreEntropy || r.isHighEntropyString(val) {
if ok, patternName := r.isSecretPattern(val); ok {
return ctx.NewIssue(lit, r.ID(), fmt.Sprintf("%s: %s", r.What, patternName), r.Severity, r.Confidence), nil
}
}
}
}
}
return nil, nil
}
// NewHardcodedCredentials attempts to find high entropy string constants being
// assigned to variables that appear to be related to credentials.
func NewHardcodedCredentials(id string, conf gosec.Config) (gosec.Rule, []ast.Node) {
@@ -390,5 +430,5 @@ func NewHardcodedCredentials(id string, conf gosec.Config) (gosec.Rule, []ast.No
Confidence: issue.Low,
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), (*ast.CompositeLit)(nil)}
}

View File

@@ -364,7 +364,123 @@ const (
func main() {
fmt.Printf("%s\n", ConfigLearnerTokenAuth)
}
`}, 0, gosec.NewConfig()},
{[]string{`
package main
type DBConfig struct {
Password string
}
func main() {
_ = DBConfig{
Password: "f62e5bcda4fae4f82370da0c6f20697b8f8447ef",
}
}
`}, 1, gosec.NewConfig()},
{[]string{`
package main
type DBConfig struct {
Password string
}
func main() {
_ = &DBConfig{
Password: "f62e5bcda4fae4f82370da0c6f20697b8f8447ef",
}
}
`}, 1, gosec.NewConfig()},
{[]string{`
package main
func main() {
_ = struct{ Password string }{
Password: "f62e5bcda4fae4f82370da0c6f20697b8f8447ef",
}
}
`}, 1, gosec.NewConfig()},
{[]string{`
package main
func main() {
_ = map[string]string{
"password": "f62e5bcda4fae4f82370da0c6f20697b8f8447ef",
}
}
`}, 1, gosec.NewConfig()},
{[]string{`
package main
func main() {
_ = map[string]string{
"apiKey": "f62e5bcda4fae4f82370da0c6f20697b8f8447ef",
}
}
`}, 1, gosec.NewConfig()},
{[]string{`
package main
type Config struct {
Username string
Password string
}
func main() {
_ = Config{
Username: "admin",
Password: "f62e5bcda4fae4f82370da0c6f20697b8f8447ef",
}
}
`}, 1, gosec.NewConfig()},
{[]string{`
package main
type DBConfig struct {
Password string
}
func main() {
_ = DBConfig{ // #nosec G101
Password: "f62e5bcda4fae4f82370da0c6f20697b8f8447ef",
}
}
`}, 0, gosec.NewConfig()},
// Negatives
{[]string{`
package main
func main() {
_ = struct{ Password string }{
Password: "secret", // low entropy
}
}
`}, 0, gosec.NewConfig()},
{[]string{`
package main
func main() {
_ = map[string]string{
"password": "secret", // low entropy
}
}
`}, 0, gosec.NewConfig()},
{[]string{`
package main
func main() {
_ = struct{ Username string }{
Username: "f62e5bcda4fae4f82370da0c6f20697b8f8447ef", // non-sensitive key
}
}
`}, 0, gosec.NewConfig()},
{[]string{`
package main
func main() {
_ = []string{"f62e5bcda4fae4f82370da0c6f20697b8f8447ef"} // unkeyed no trigger
}
`}, 0, gosec.NewConfig()},
}
@@ -430,6 +546,24 @@ func main() {
if compareGoogleAPI == "AIzajtGS_aJGkoiAmSbXzu9I-1eytAi9Lrlh-vT" {
fmt.Println(compareGoogleAPI)
}
}
`}, 1, gosec.NewConfig()},
{[]string{`
package main
func main() {
_ = struct{ SomeKey string }{
SomeKey: "AKIAI44QH8DHBEXAMPLE",
}
}
`}, 1, gosec.NewConfig()},
{[]string{`
package main
func main() {
_ = map[string]string{
"github_token": "ghp_iR54dhCYg9Tfmoywi9xLmmKZrrnAw438BYh3",
}
}
`}, 1, gosec.NewConfig()},
}