Skip to content

Add security CI baseline and adversarial recovery evals#80

Merged
TeoSlayer merged 2 commits into
mainfrom
ci-security-hardening
Jun 22, 2026
Merged

Add security CI baseline and adversarial recovery evals#80
TeoSlayer merged 2 commits into
mainfrom
ci-security-hardening

Conversation

@TeoSlayer

Copy link
Copy Markdown
Contributor

Hardens CI security and adds adversarial/fuzz EVAL coverage for the registry's
badge / identity-recovery security logic. No behavior change to the registry
beyond a Go toolchain bump.

Security CI baseline (new gating jobs)

New security.yml (push + PR to main), official actions pinned to commit SHAs:

Job Tool Notes
codeql github/codeql-action (Go, security-and-quality) uploads to code scanning
gosec SAST securego/gosec v2.22.9 -conf .gosec.json -severity medium -confidence medium
govulncheck golang.org/x/vuln call-graph vuln scan
gitleaks secret scan gitleaks/gitleaks-action v2 full-history diff scan

New dependency-review.yml (PR only): actions/dependency-review-action,
fail-on-severity: high. .github/dependabot.yml (gomod + github-actions
weekly) already existed and is left as-is.

ci.yml: the existing test gate now runs go test -race -parallel 4 ...
(project convention — unbounded parallelism exhausts ephemeral ports/sockets
in the registry integration tests).

Suggested required status checks

test (existing), CodeQL (Go), gosec SAST, govulncheck,
gitleaks secret scan, Dependency Review.

Scanner findings + resolutions

  • govulncheck: flagged GO-2026-5039 (net/textproto) and GO-2026-5037
    (crypto/x509), both stdlib, both fixed in go1.25.11. Resolved by bumping the
    toolchain directive to go1.25.11; govulncheck then reports clean.
  • gosec: 68 findings on first run. All fall into accepted rule classes for
    a registry server; excluded in .gosec.json with per-rule justification
    (nothing blanket-disabled, no inline #nosec). The -severity medium gate
    still fails the job on any future finding outside these classes.
    • G104 (50, LOW) — unhandled errors on best-effort socket tuning / Close()
      in defers / error frames on connections already being dropped.
    • G115 (9, HIGH) — uint32(len(...)) of frames capped at 64KB
      (wire.MaxMessageSize) and bounded JSON-decoded ids; cannot overflow.
    • G304 (6, MEDIUM) — reads of operator-supplied config/WAL/whitelist paths.
    • G306 (2, MEDIUM) — registry.json / dashboard snapshot written 0644 by
      design (operator-readable, no secrets).
    • G114 (1, MEDIUM) — dashboard http.Serve without per-request timeouts;
      enforced at the proxy/breaker layer.
  • go vet: pre-existing finding in dashboard/zz_public_stats_test.go
    (resp used before error check — nil-deref on http.Get failure). Fixed.

Adversarial / fuzz evals added

Extends the PR #79 suite (no duplication):

  • FuzzRecoveryWireDecode (identity) — fuzzes the JSON decode +
    argument-extraction path of submit_badge / enroll_recovery /
    recover_identity. Asserts no input panics and that, with verifiers stubbed
    to reject, no handler ever returns success (fail-closed) and the pinned
    key/badge are never mutated. ~19k execs clean locally.
  • TestHandleRecoverIdentityRejectsExpiryBeyondWindow + positive control —
    a recovery Exp past the 30-min maxRecoveryWindow is rejected before the
    nonce is consumed or the binding touched; an in-window Exp still succeeds.
  • TestHandleBinaryLookup_DoesNotLeakExternalID (directory) — privacy
    regression guard for the BINARY lookup path (the JSON path was already
    covered): the decoded LookupResp carries an empty external_id even when
    the node holds a raw external identity.

Already covered by PR #79 (confirmed present, not duplicated): unauthenticated
owner-reclaim pubkey-rebind rejected with binding unchanged; same-key
re-register no-regression; nonce single-use + replay-across-reload; recovered
identity badge cleared (incl. WAL key-rotation delta replay path).

Validation (local, GOWORK=off, go1.25.11)

  • go build ./... clean; go vet ./... clean; new files gofmt-clean.
  • go test -race -parallel 4 ./... — all packages pass.
  • gosec -conf .gosec.json -severity medium -confidence medium ./... — 0 issues.
  • govulncheck ./... — no vulnerabilities.
  • FuzzRecoveryWireDecode — ran 10s, no panics, no fail-open.

Repo-wide pre-existing gofmt drift (unrelated files) is intentionally left
untouched; no gofmt gate is added so CI stays green.

CI baseline (pinned official actions):
- security.yml: CodeQL (Go), gosec SAST, govulncheck, gitleaks
- dependency-review.yml on PRs
- ci.yml test gate now uses -parallel 4 (port/socket exhaustion)
- bump toolchain to go1.25.11 (clears GO-2026-5039/5037 stdlib vulns)
- .gosec.json excludes accepted rule classes with per-rule justification

Adversarial evals for the registry security logic:
- FuzzRecoveryWireDecode: fuzz submit_badge/enroll_recovery/
  recover_identity decode path; assert no panic and fail-closed
- recovery exp beyond 30-min window rejected before nonce consume
- binary lookup path does not leak external_id (privacy guard)

Fix pre-existing go vet finding in dashboard public-stats test.
@github-advanced-security

Copy link
Copy Markdown

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:

  • The 'Security' tab will display more code scanning analysis results (e.g., for the default branch).
  • Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results.
  • You will be able to see the analysis results for the pull request's branch on this overview once the scans have completed and the checks have passed.

For more information about GitHub Code Scanning, check out the documentation.

@codecov

codecov Bot commented Jun 22, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

The gitleaks GitHub Action needs a paid GITLEAKS_LICENSE for org repos;
run the MIT-licensed binary directly instead (same scan, no license).

dependency-review-action requires the repo Dependency Graph to be
enabled; mark it continue-on-error so the prerequisite does not red CI,
with instructions to gate it once the graph is on.
@TeoSlayer TeoSlayer merged commit 590bf51 into main Jun 22, 2026
9 checks passed
@matthew-pilot matthew-pilot deleted the ci-security-hardening branch June 22, 2026 15:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants