harden(security): close RCE gate gap + supply-chain/scan hardening#26
Merged
Conversation
SOC 3 / OWASP gap remediation from a full-repo security audit. - fix(security): gate config-supplied govulncheck_command through trust.GuardConfigCommand. It was exec'd ungated and default-on for Go targets, an RCE for untrusted PRs. Built-in default binary stays exempt. - ci: SHA-pin every third-party GitHub Action (incl. setup-homebrew@main); SLSA generator stays tag-pinned by design. - ci(release): move untrusted tag input into env:, gate auto-tag creation behind a create_missing_tag input set only by trusted callers, scope job permissions to least privilege, pass secrets explicitly. - build(docker): digest-pin base images and run as non-root USER. - docs: add SECURITY.md (disclosure policy) and .github/CODEOWNERS. - fix(config): make artifact-path containment symlink-aware (EvalSymlinks on base + deepest existing ancestor) to close a committed-symlink escape. - perf(scan): skip files over 32 MiB in the walk and read via a bounded reader to prevent memory exhaustion on untrusted repos. - feat(report): emit SARIF tool version + invocations for run attribution. Adds regression tests for each. Verified: build, vet, gofmt, go test (505), golangci-lint (0 issues), self-scan `make codeguard-ci` (0 fails). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.
Summary
Remediation of a full-repo SOC 3 / OWASP security audit. Closes one confirmed critical RCE plus supply-chain, path-traversal, DoS, and audit-trail gaps. Each fix ships with a regression test.
Changes
🔴 Critical
security_rules.govulncheck_commandwas passed straight toexecwith no trust gate and is default-on for Go targets, so an untrusted PR editingcodeguard.yamlcould run arbitrary commands in CI.govulncheck.Runnow routes a config-supplied override throughtrust.GuardConfigCommand; the built-ingovulncheckbinary (resolved from PATH, a static analyzer that doesn't execute scanned code) stays exempt so defaultautomode keeps working.🟠 Supply chain (OWASP A08 / SOC 3 change management)
Homebrew/actions/setup-homebrew@main. The SLSA generator remains version-tag-pinned by design (documented inline).release.ymlhardened: untrusted tag input moved out ofrun:intoenv:; auto-tag creation gated behind a newcreate_missing_taginput that only the trustedcd.ymlcallers set (a manual dispatch can no longer mint an arbitrary tag from an arbitrary SHA); top-level permissions reduced tocontents: readwith per-job elevation;secrets: inheritreplaced with explicitRELEASE_PLEASE_TOKENpassing.USER.🟡 Governance / robustness
SECURITY.md(private disclosure policy + SLAs) and.github/CODEOWNERS.config.containedPathnow canonicalizes symlinks (base + deepest existing ancestor), closing a committed-symlink escape of thebaseline/cache/ai.cachepath guarantee. Adds the previously-missingcache.path/ai.cache.pathcoverage.WalkFilesskips files > 32 MiB and reads go through a bounded reader, preventing a giant file in an untrusted PR from OOMing the in-memory corpus.driver.version/informationUri+ aninvocationsrecord so a CI consumer can attribute results to a specific run (A09 / monitoring).Not included (deliberate)
main(0 required approvals, no required status checks, no code-owner review); tightening it is a separate policy call.Test plan
go build ./...,go vet ./...,gofmt -l— cleango test ./...— 505 pass (new tests: govulncheck gate, cache/ai-cache + symlink containment, scan file cap, SARIF invocation)golangci-lint run(incl. gosec) — 0 issuesmake codeguard-ci— 0 fails (updated.codeguard/codeguard.yamlrequired-workflow marker to match the SHA-pinned action)Knowledge
Updated
.claude/knowledge/architecture-boundaries.md: corrected two stale entries (one claimed govulncheck was "not gated" — that was the bug) and documented the new corpus-walk size cap.🤖 Generated with Claude Code