fix(security): pin actions to SHAs, scope tokens, broaden credential redaction - #609
Merged
Merged
Conversation
…redaction
Supply chain. Every third-party action ran from a mutable tag, including
the ones that hold credentials: docker/login-action, cosign-installer,
attest-build-provenance and build-push-action. A tag can be repointed by
whoever controls the action repo, so the release path trusted a moving
target. All 24 refs now pin a commit SHA with the version in a comment.
Token scope. ci.yml, docker.yml, release-drafter.yml and sbom.yml had no
top-level permissions block, so any job without its own block inherited
the repository default. The three that do declare job-level permissions
keep them; the top-level contents: read is the floor, not a change to
what those jobs can do.
Shell injection. release.yml and release-drafter.yml substituted
github.event.release.tag_name and github.ref_name straight into run:
blocks. ${{ }} expands before bash parses the line, so those names were
shell input. All four sites now pass through env.
HW-008 redaction was an Authorization special case, but the same request
is configured with OPAQUE_API_KEY, and a deployment carrying it under
x-api-key or a cookie would have logged it in clear on the debug path.
Redaction is now deny-by-default over a name match, with a parametrized
test over the spellings that leaked.
The TLS pinning fixture built its server with PROTOCOL_TLS_SERVER and no
floor, leaving TLSv1 and TLSv1.1 reachable in a test that exists to prove
the gateway's transport rules. Sets minimum_version to TLSv1.2.
Closes code-scanning alerts #136 and #2.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XbDBXDWWvMFa7c2jGgyq9t
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.
Part of a proactive security sweep across agentrust-io. cmcp had the largest share of the real findings.
Action pinning (24 refs)
Every third-party action ran from a mutable tag. The ones that matter are on the release path and hold credentials:
docker/login-action@v4(registry credentials)sigstore/cosign-installer@v3(signing)actions/attest-build-provenance@v4(id-token: write)docker/build-push-action@v7A tag is repointable by whoever controls the action repo, so signing and publishing trusted a moving target. All now pin a commit SHA with the version kept in a trailing comment.
Token scope
ci.yml,docker.yml,release-drafter.ymlandsbom.ymlhad no top-levelpermissions:block, so any job without its own block inherited the repository default. Addedcontents: readas the floor.docker.ymlandsbom.ymlalready declared job-levelpackages: write/id-token: writeand keep them, so no job loses a capability it was using.Shell injection
Four sites interpolated
github.event.release.tag_nameorgithub.ref_namedirectly intorun:blocks.${{ }}expands before bash parses the line, so those names were shell input rather than arguments. All now go throughenv:.Defence in depth rather than a live hole, since creating a tag or release already needs write access.
Credential redaction (code-scanning #136)
_redact_auth_headersredacted onlyAuthorization. The same call is configured withOPAQUE_API_KEY, so a deployment carrying it inx-api-key,x-auth-tokenor a cookie would have written it to the debug log in clear. Redaction is now deny-by-default over a name match, with a parametrized test across the spellings that leaked and a companion test proving non-credential headers stay readable, since blinding that log would cost the failure diagnostics it exists for.TLS floor (code-scanning #2)
The pinning fixture built its server with
PROTOCOL_TLS_SERVERand no floor, leaving TLSv1 and TLSv1.1 reachable in the very test that asserts the gateway transport rules. Setsminimum_version = TLSv1_2.Verification
tests/unit/test_tls_pinning.py12 passed,test_opaque_fail_closed_594.py29 passed. Full suite 1604 passed with 4 failures that reproduce on a clean checkout ofmain: the local venv has agent-manifest 0.11.1 against a>=0.11.2pin. Unrelated to this change, and CI installs the pin.🤖 Generated with Claude Code
https://claude.ai/code/session_01XbDBXDWWvMFa7c2jGgyq9t