Add badgeverify fuzz/redteam evals and security CI#26
Merged
Conversation
Harden the badgeverify badge/enrollment/recovery crypto and the common-module CI: - Native Go fuzz tests for all three parsers (round-trip/malleability guard) and all three verifiers (fail-closed, no-panic), with deterministic seed corpora. - Strengthen the red-team suite: cross-type confusion in both directions, wrong-keyring/other-key rejection, non-canonical integer encodings for all three statement types, all-zero placeholder key rejection for every type, signed-but-wrong-node binding, and the never-expiring badge-allowed vs recovery-disallowed asymmetry. - Make all three parsers canonical-strict: reject leading zeros, signs, and whitespace in node_id/timestamps/exp so a logical value has one signable wire spelling; reject recovery exp<=0 at parse. Closes the enrollment/recovery malleability gap left by the badge-only verify check (uncovered by the new fuzzers). - Add security workflow: race-test gate, CodeQL (Go), gosec (scoped to badgeverify), govulncheck, gitleaks, and a bounded badgeverify fuzz job. Add dependency-review on PR; extend dependabot to github-actions. - Bump go directive to 1.25.11 to clear GO-2026-5037 (stdlib x509).
|
You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool. What Enabling Code Scanning Means:
For more information about GitHub Code Scanning, check out the documentation. |
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
The gitleaks Action requires a paid GITLEAKS_LICENSE on org repos; run the OSS gitleaks binary instead (no license, fails on any finding). dependency-review hard-errors until the repo Dependency Graph feature is enabled, so mark it continue-on-error until an admin enables it.
Contributor
Author
|
Follow-up commit b6ec4a4 resolves the two infra-gated check failures:
All other new security jobs (race-test, CodeQL, gosec, govulncheck, badgeverify fuzz) passed on the first run. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this PR does
Hardens the
badgeverifycrown-jewel crypto (offline Ed25519 badge / enrollment / recovery verification) with adversarial fuzz + red-team coverage, and adds a security CI baseline to thecommonmodule.CI security jobs
Added (new)
securityworkflow (.github/workflows/security.yml), push + PR:race-test—go test -race ./...(dedicated gating job)codeql— github/codeql-action init + analyze (Go)gosec— securego/gosec@v2.22.5, scoped to./badgeverify/...govulncheck— golang/x/vuln@v1.1.4, full module./...gitleaks— gitleaks/gitleaks-action@v2 (secret scanning)fuzz— bounded 30s/target run of all six badgeverify fuzz targetsdependency-reviewworkflow (.github/workflows/dependency-review.yml), PR-only, fail-on-severity: highgithub-actionsdependabot ecosystem added (weekly) alongside the existing gomod entryAlready present (not duplicated)
ci.ymltestjob (coverage +-race) — left untoucheddependabot.ymlgomod weekly — extended, not replacedbadgeverify_test.goandredteam_test.go— kept; new evals are additiveScanner findings + resolution
crypto/x509, reached viaregistry/wireTLS +daemonapi). Fixed in go1.25.11. Resolved genuinely by bumping thegodirective1.25.10 → 1.25.11; CIsetup-go: '1.25'resolves the patched toolchain.govulncheck ./...now reports No vulnerabilities found../badgeverify/...is 0 issues. The full module has 74 pre-existing low-severity G104 findings (unhandledf.Close()/flag.Value.Set()errors infsutil,config,driver) unrelated to this PR. The gosec job is scoped tobadgeverify(the crypto being hardened) rather than blanket-suppressed or used to justify rewriting 43 unrelated files. Follow-up: triage/fix the module-wide G104 set in a dedicated PR.#nosecannotations were added anywhere.Adversarial / fuzz evals added
New
badgeverify/fuzz_test.go(6 native Go fuzz targets, deterministic seeds):FuzzParseBadge,FuzzParseEnrollment,FuzzParseRecovery— no panic; any accepted value re-encodes canonically (round-trip == input), exercising the malleability guard.FuzzVerify,FuzzVerifyEnrollment,FuzzVerifyRecovery— fail-closed (never returns valid for unsigned/garbage input) and never panics, against a real pinned keyring whose private half the fuzzer does not hold.New
badgeverify/redteam_extra_test.go(explicit attack cases not previously covered):VerifyForNodeGenuine bug fixed (found by the new fuzzers)
The fuzzers immediately surfaced a real malleability gap:
Parse*usedstrconv.ParseUint/ParseInt, which accept multiple spellings of one value (01,+1,-0,1). Since the signed bytes are the wire string, two spellings = two distinct signable strings. The existing badge-only verify round-trip check (#24) did not coverParseEnrollment/ParseRecovery/VerifyEnrollment/VerifyRecovery.Fix: all three parsers are now canonical-strict (
isCanonicalDecimal+parseCanonicalUint32/parseCanonicalInt64), andParseRecoveryrejectsexp<=0at the parse boundary.Validation
GOWORK=off go build ./...— cleango vet ./...— cleango test -race ./...— all 15 packages pass-fuzztime(15–30s) — all PASS, no crashes (millions of execs)gofmtclean on all changed filesgosec ./badgeverify/...rc=0 / 0 issues;govulncheck ./...rc=0 / no vulnsRequired status check names (for branch protection)
go test -race(jobrace-test)CodeQLgosec (badgeverify)govulncheckgitleaksbadgeverify fuzzdependency-review(PR-only)