Skip to content

CI security scanning

afmpeg's merge-request gate runs several security scanners from the phpboyscout/cicd go-security component. This page explains what each does and records the non-obvious decisions, especially the osv-scanner handling, which cost real debugging time and is worth not re-deriving.

The scanners

Job Tool Scope Reachability-aware?
govulncheck Go's official scanner stdlib + imported packages Yes, call-graph aware
osv-scanner Google OSV-DB go.mod (declared deps) No, module/lockfile level
trivy Aqua vuln DB filesystem No
gitleaks secret-pattern scan git history n/a

govulncheck and osv-scanner overlap deliberately: govulncheck is precise (it only reports advisories your code actually reaches), osv-scanner is broad (it reports every advisory against a declared dependency, reachable or not). A finding in osv-scanner that govulncheck stays silent on is almost always an unreachable advisory.

The GO-2026-5932 decision (x/crypto)

Symptom. Since a vuln-DB update, osv-scanner failed every MR on GO-2026-5932 in golang.org/x/crypto (v0.53.0), while govulncheck did not flag it.

Why it can't be dropped. x/crypto is not a stray dependency. It is the foundation of the OpenPGP release-verification stack:

pkg/afmpeg
  → gitlab.com/phpboyscout/go/signing/verify     (WithModuleRelease / WKD — specs 0010/0011)
    → github.com/ProtonMail/go-crypto/openpgp     (OpenPGP)
      → golang.org/x/crypto/hkdf

It is additionally pulled by cloudflare/circl, golang.org/x/net (the HTTP/2 download path) and golang.org/x/mod. Removing it means removing signed-release verification. And there is no fixed version upstream (FIXED VERSION: --), so a bump cannot help either.

Why ignoring it is correct, not a shortcut. govulncheck, which is call-graph aware, confirms afmpeg never calls the affected symbol: only x/crypto/hkdf is linked, not the vulnerable function. So the finding is an unreachable, unfixable, undroppable module-level false positive. That is exactly what an ignore entry is for. Reachability is still enforced, by govulncheck.

The waiver is not carried here per-repo: it ships in the go-security component itself (from cicd v0.21.0), which applies it to every consumer. afmpeg therefore keeps no local .osv-scanner.toml. Revisit when x/crypto ships a fix, that removal happens in the component, not here.

The two osv-scanner gotchas (now handled by the component)

Getting osv-scanner green took more than an ignore entry, and the debugging is worth keeping even though the fix now lives upstream. The go-security component used to run /osv-scanner -L go.mod, and two things broke, both fixed in cicd v0.21.0 (spec: the component's osv-scanner-toolchain-and-waiver):

  1. Config not applied. osv-scanner does not auto-discover .osv-scanner.toml for a -L (lockfile) scan, and the job passed no --config, so any ignore list was silently inert. The component now appends its global waivers to the repo's .osv-scanner.toml (creating it if absent) and always passes --config, so per-repo ignores work too.

  2. Exit 127 from a failed internal build. osv-scanner runs its own govulncheck for call-analysis, which builds the module using the Go toolchain bundled in the scanner image (GOTOOLCHAIN=local). Once go.mod required Go 1.26.5, that build failed inside the older-Go scanner image (go.mod requires go >= 1.26.5 (running go 1.26.4; GOTOOLCHAIN=local)), and osv-scanner exited 127, but only after the ignore emptied the result set (with findings present it exits 1, masking the error). The component now defaults osv_scanner_call_analysis to false (passing --no-call-analysis=all): that reachability step is redundant (the dedicated govulncheck job already provides it) and it fragilely couples the scanner image's Go to go.mod's requirement.

afmpeg briefly carried these as a local osv-scanner: job override; that override (and the local .osv-scanner.toml) were removed once it adopted go-security @v0.21.0.

The Go 1.26.5 bump

Separately, GO-2026-5856 and GO-2026-4970 are standard-library advisories fixed in Go 1.26.5, so they can only be cleared by the toolchain. Bumping go.mod's go directive to 1.26.5 cleared both (govulncheck green, osv-scanner stdlib findings gone). The shared dev-tools image resolves the 1.26.5 toolchain fine (GOTOOLCHAIN=auto), so the bump did not break the Go jobs; it only tripped osv-scanner's bundled-Go call-analysis, per gotcha 2.

Rule of thumb for the next scanner failure

  1. Does govulncheck also flag it? If yes, it's reachable, so fix it (bump or patch), don't ignore.
  2. osv-scanner-only + a fixed version exists → bump the dep.
  3. osv-scanner-only + no fix + govulncheck silent + undroppable → ignore with a dated ignoreUntil and record why here.
  4. A scanner failing on infrastructure (toolchain version, exit-code quirk), not a real finding → fix it in .gitlab-ci.yml, and note the cause so the next person doesn't re-debug it.