# nosec 抑制是非确定性的(相同源,相同二进制文件)
Running gosec repeatedly over unchanged source produces different results.
A G101 finding that is covered by a #nosec G101 directive is correctly suppressed on most runs, but leaks through as a reported issue on a minority of runs — no source change, no flag change, same gosec binary.
This makes gosec unusable as a hard CI gate: a job that runs gosec ./... and fails on any HIGH finding flakes red at random.
Environment
- gosec: v2.29.0 (also reproduces on
@latestbuilt from source) - Go:
go1.26.8(also seen on 1.22/1.23) - OS: reproduced on macOS (arm64) and Ubuntu (GitHub-hosted
ubuntu-latest)
Minimal reproduction
Self-contained package (stdlib only, compiles, go vet-clean):
package repro
import (
"fmt"
"net/url"
"os"
)
// #nosec G101 -- example connection strings in help text are not real credentials
var serveCmd = &struct {
Use, Long string
RunE func(args []string) error
}{
Use: "serve",
Long: `Config file format:
databases:
db1:
url: "postgres://user:pass@host:5432/db1"
db2:
url: "postgres://user:pass@host:5432/db2"
`,
RunE: func(args []string) error {
cfgPath := os.Getenv("CFG")
raw, err := os.ReadFile(cfgPath) // #nosec G304 -- operator-supplied path
if err != nil {
return fmt.Errorf("read: %w", err)
}
_ = raw
u, _ := url.Parse(os.Getenv("DB_URL"))
if u != nil && u.User != nil {
u.User = url.UserPassword(u.User.Username(), "x")
}
return nil
},
}
func main() { _ = serveCmd }Run gosec ~50–60 times and count the G101 findings each run:
for i in $(seq 1 60); do
gosec -fmt json -out out.json ./... >/dev/null 2>&1 || true
python3 -c "import json;print(len([x for x in json.load(open('out.json'))['Issues'] if x['rule_id']=='G101']),end=' ')"
done; echoA ready-made script (reproduce.sh) that generates the package, runs gosec N times, and exits non-zero when the outcome varies is attached.
Expected
Every run yields the identical result. The #nosec G101 directive covers the declaration, so the G101 finding should be suppressed on every run (count 0).
Actual
The G101 count varies run to run over identical source, e.g.:
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 00 = directive honored (correct); 1 = same directive ignored, finding leaks. Leak rate is roughly 5–15% per run and rises with more concurrent CPU load.
On the real-world codebase where we first hit this, the same file flapped between 9 and 10 total findings across 50 CI runs — one suppressed G101 appearing/disappearing — which is what led us here.
What appears to matter (from bisecting)
The bug only surfaces with a …
内容来源: securego/gosec