From b21c752d7faed42f6f2f0fe5e04c050d2b68d6ce Mon Sep 17 00:00:00 2001 From: Ville Vesilehto Date: Tue, 30 Dec 2025 00:01:27 +0200 Subject: [PATCH] chore(lint): enable gosec (#7792) Enable "gosec" linter. Exclude: - All G115 (integer overflow) findings, to be fixed separately. Add targeted gosec annotations for: - non-crypto math/rand usage - md5 used only for file change detection - G114 ("net/http serve with no timeout settings"), to be fixed separately. Other findings fixed. Signed-off-by: Ville Vesilehto --- .golangci.yml | 5 +++++ plugin/chaos/chaos.go | 2 +- plugin/dnstap/io.go | 1 + plugin/file/secondary.go | 2 +- plugin/health/health.go | 1 + plugin/loadbalance/weighted.go | 6 +++--- plugin/pkg/rand/rand.go | 2 +- plugin/pkg/tls/tls.go | 11 +++++++++-- plugin/pprof/pprof.go | 1 + plugin/ready/ready.go | 1 + plugin/reload/setup.go | 2 +- plugin/sign/setup.go | 4 ++-- plugin/test/file.go | 12 ++++++++---- 13 files changed, 35 insertions(+), 15 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 697c0c9fe..e32b54e5a 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -11,6 +11,7 @@ linters: - copyloopvar - durationcheck - godoclint + - gosec - govet - ineffassign - intrange @@ -39,7 +40,11 @@ linters: - path: _test\.go linters: - perfsprint + - gosec settings: + gosec: + excludes: + - G115 govet: enable: - nilness diff --git a/plugin/chaos/chaos.go b/plugin/chaos/chaos.go index f4d758a7b..ff8354a64 100644 --- a/plugin/chaos/chaos.go +++ b/plugin/chaos/chaos.go @@ -36,7 +36,7 @@ func (c Chaos) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) ( default: return plugin.NextOrFailure(c.Name(), c.Next, ctx, w, r) case "authors.bind.": - rnd := rand.New(rand.NewSource(time.Now().Unix())) + rnd := rand.New(rand.NewSource(time.Now().Unix())) // #nosec G404 -- non-cryptographic randomness for shuffling authors. for _, i := range rnd.Perm(len(c.Authors)) { m.Answer = append(m.Answer, &dns.TXT{Hdr: hdr, Txt: []string{c.Authors[i]}}) diff --git a/plugin/dnstap/io.go b/plugin/dnstap/io.go index 1987b4d43..751631c76 100644 --- a/plugin/dnstap/io.go +++ b/plugin/dnstap/io.go @@ -70,6 +70,7 @@ func (d *dio) dial() error { if d.proto == "tls" { config := &tls.Config{ + // #nosec G402 -- optional, user-configurable escape hatch for environments that cannot validate certs. InsecureSkipVerify: d.skipVerify, } dialer := &net.Dialer{ diff --git a/plugin/file/secondary.go b/plugin/file/secondary.go index b95248e8c..6c4b06d64 100644 --- a/plugin/file/secondary.go +++ b/plugin/file/secondary.go @@ -195,7 +195,7 @@ Restart: // jitter returns a random duration between [0,n) * time.Millisecond func jitter(n int) time.Duration { - r := rand.Intn(n) + r := rand.Intn(n) // #nosec G404 -- non-cryptographic jitter to spread transfer attempts. return time.Duration(r) * time.Millisecond } diff --git a/plugin/health/health.go b/plugin/health/health.go index 980cf2bc8..08a124010 100644 --- a/plugin/health/health.go +++ b/plugin/health/health.go @@ -63,6 +63,7 @@ func (h *health) OnStartup() error { ctx := context.Background() ctx, h.stop = context.WithCancel(ctx) + // #nosec G114 -- TODO go func() { http.Serve(h.ln, h.mux) }() go func() { h.overloaded(ctx) }() diff --git a/plugin/loadbalance/weighted.go b/plugin/loadbalance/weighted.go index 275af6f88..9f72a7dc3 100644 --- a/plugin/loadbalance/weighted.go +++ b/plugin/loadbalance/weighted.go @@ -3,7 +3,7 @@ package loadbalance import ( "bufio" "bytes" - "crypto/md5" + "crypto/md5" // #nosec G501 -- used only as a checksum for file change detection (not for security). "errors" "fmt" "io" @@ -52,7 +52,7 @@ type randomUint struct { } func (r *randomUint) randInit() { - r.rn = rand.New(rand.NewSource(time.Now().UnixNano())) + r.rn = rand.New(rand.NewSource(time.Now().UnixNano())) // #nosec G404 -- non-cryptographic randomness for load balancing. } func (r *randomUint) randUint(limit uint) uint { @@ -245,7 +245,7 @@ func (w *weightedRR) updateWeights() error { if err != nil { return err } - md5sum := md5.Sum(bytes) + md5sum := md5.Sum(bytes) // #nosec G401 -- used only as a checksum for file change detection (not for security). if md5sum == w.md5sum { // file contents has not changed return nil diff --git a/plugin/pkg/rand/rand.go b/plugin/pkg/rand/rand.go index f7332adf5..de20d771d 100644 --- a/plugin/pkg/rand/rand.go +++ b/plugin/pkg/rand/rand.go @@ -17,7 +17,7 @@ type Rand struct { // New returns a new Rand from seed. func New(seed int64) *Rand { - return &Rand{r: rand.New(rand.NewSource(seed))} + return &Rand{r: rand.New(rand.NewSource(seed))} // #nosec G404 -- non-cryptographic RNG by design (load balancing only). } // Int returns a non-negative pseudo-random int from the Source in Rand.r. diff --git a/plugin/pkg/tls/tls.go b/plugin/pkg/tls/tls.go index 41eff4bc0..a2a955f05 100644 --- a/plugin/pkg/tls/tls.go +++ b/plugin/pkg/tls/tls.go @@ -95,7 +95,11 @@ func NewTLSConfig(certPath, keyPath, caPath string) (*tls.Config, error) { return nil, err } - tlsConfig := &tls.Config{Certificates: []tls.Certificate{cert}, RootCAs: roots} + // #nosec G402 -- MinVersion and MaxVersion are set in setTLSDefaults + tlsConfig := &tls.Config{ + Certificates: []tls.Certificate{cert}, + RootCAs: roots, + } setTLSDefaults(tlsConfig) return tlsConfig, nil @@ -109,7 +113,10 @@ func NewTLSClientConfig(caPath string) (*tls.Config, error) { return nil, err } - tlsConfig := &tls.Config{RootCAs: roots} + // #nosec G402 -- MinVersion and MaxVersion are set in setTLSDefaults + tlsConfig := &tls.Config{ + RootCAs: roots, + } setTLSDefaults(tlsConfig) return tlsConfig, nil diff --git a/plugin/pprof/pprof.go b/plugin/pprof/pprof.go index 822e6e222..f09d98222 100644 --- a/plugin/pprof/pprof.go +++ b/plugin/pprof/pprof.go @@ -43,6 +43,7 @@ func (h *handler) Startup() error { runtime.SetBlockProfileRate(h.rateBloc) go func() { + // #nosec G114 -- TODO http.Serve(h.ln, h.mux) }() return nil diff --git a/plugin/ready/ready.go b/plugin/ready/ready.go index 16472f425..3872a040d 100644 --- a/plugin/ready/ready.go +++ b/plugin/ready/ready.go @@ -61,6 +61,7 @@ func (rd *ready) onStartup() error { io.WriteString(w, notReadyPlugins) }) + // #nosec G114 -- TODO go func() { http.Serve(rd.ln, rd.mux) }() return nil diff --git a/plugin/reload/setup.go b/plugin/reload/setup.go index 0cbecc6a4..65cd68149 100644 --- a/plugin/reload/setup.go +++ b/plugin/reload/setup.go @@ -60,7 +60,7 @@ func setup(c *caddy.Controller) error { j = i / 2 } - jitter := time.Duration(rand.Int63n(j.Nanoseconds()) - (j.Nanoseconds() / 2)) + jitter := time.Duration(rand.Int63n(j.Nanoseconds()) - (j.Nanoseconds() / 2)) // #nosec G404 -- non-cryptographic jitter. i = i + jitter // prepare info for next onInstanceStartup event diff --git a/plugin/sign/setup.go b/plugin/sign/setup.go index ed3e6bda0..76c0a3a9a 100644 --- a/plugin/sign/setup.go +++ b/plugin/sign/setup.go @@ -62,8 +62,8 @@ func parse(c *caddy.Controller) (*Sign, error) { signers[i] = &Signer{ dbfile: dbfile, origin: origins[i], - jitterIncep: time.Duration(float32(durationInceptionJitter) * rand.Float32()), - jitterExpir: time.Duration(float32(durationExpirationDayJitter) * rand.Float32()), + jitterIncep: time.Duration(float32(durationInceptionJitter) * rand.Float32()), // #nosec G404 -- non-cryptographic jitter. + jitterExpir: time.Duration(float32(durationExpirationDayJitter) * rand.Float32()), // #nosec G404 -- non-cryptographic jitter. directory: "/var/lib/coredns", stop: make(chan struct{}), signedfile: fmt.Sprintf("db.%ssigned", origins[i]), // origins[i] is a fqdn, so it ends with a dot, hence %ssigned. diff --git a/plugin/test/file.go b/plugin/test/file.go index 93fce6c08..b34d4d4d5 100644 --- a/plugin/test/file.go +++ b/plugin/test/file.go @@ -12,7 +12,10 @@ func TempFile(dir, content string) (string, func(), error) { if err != nil { return "", nil, err } - if err := os.WriteFile(f.Name(), []byte(content), 0644); err != nil { + if err := f.Close(); err != nil { + return "", nil, err + } + if err := os.WriteFile(f.Name(), []byte(content), 0600); err != nil { return "", nil, err } rmFunc := func() { os.Remove(f.Name()) } @@ -43,7 +46,7 @@ xGbtCkhVk2VQ+BiCWnjYXJ6ZMzabP7wiOFDP9Pvr2ik22PRItsW/TLfHFXM1jDmc I1rs/VUGKzcJGVIWbHrgjP68CTStGAvKgbsTqw7aLXTSqtPw88N9XVSyRg== -----END CERTIFICATE-----` path := filepath.Join(tempDir, "ca.pem") - if err := os.WriteFile(path, []byte(data), 0644); err != nil { + if err := os.WriteFile(path, []byte(data), 0600); err != nil { return "", err } data = `-----BEGIN CERTIFICATE----- @@ -64,10 +67,11 @@ zhDEPP4FhY+Sz+y1yWirphl7A1aZwhXVPcfWIGqpQ3jzNwUeocbH27kuLh+U4hQo qeg10RdFnw== -----END CERTIFICATE-----` path = filepath.Join(tempDir, "cert.pem") - if err := os.WriteFile(path, []byte(data), 0644); err != nil { + if err := os.WriteFile(path, []byte(data), 0600); err != nil { return "", err } + //nolint:gosec // Test fixture private key. data = `-----BEGIN RSA PRIVATE KEY----- MIIEpgIBAAKCAQEAxPBrvAIWiIJp383ndpRF+OuZ74pHsVLTJ/lSv05H+gzcGhL2 y1i7kWXOvfmgvlPq3kZzZ7LvyZSz8KzTumyeNR0ofnlsOklJ0bvNb2Zc3J4vAh58 @@ -96,7 +100,7 @@ E/WObVJXDnBdViu0L9abE9iaTToBVri4cmlDlZagLuKVR+TFTCN/DSlVZTDkqkLI 8chzqtkH6b2b2R73hyRysWjsomys34ma3mEEPTX/aXeAF2MSZ/EWT9yL -----END RSA PRIVATE KEY-----` path = filepath.Join(tempDir, "key.pem") - if err := os.WriteFile(path, []byte(data), 0644); err != nil { + if err := os.WriteFile(path, []byte(data), 0600); err != nil { return "", err }