scan-plugins Composite GitHub Action: Automated Safety Scanning for Claude Plugins
The scan-plugins composite GitHub Action is a reusable workflow component that automatically inspects Claude-compatible plugins for safety and policy compliance before they are merged, combining deterministic static analysis with optional AI-powered policy verification.
Maintained in the anthropics/claude-plugins-community repository, this action serves as a critical CI gatekeeper for plugin submissions. It validates that external plugin entries meet security standards by checking for floating runtime dependencies and enforcing custom policy rules through Anthropic’s Claude CLI.
Two-Stage Security Model
The action operates through two distinct stages that run sequentially, allowing secure validation even in environments without API credentials.
Static Pin Check (Auth-Free)
The first stage performs deterministic analysis on every changed external plugin entry defined in .github/actions/scan-plugins/action.yml (lines 48-65). For each plugin, the action clones the exact commit at the pinned SHA and examines the .mcp.json declaration for floating launchers such as npx, uvx, bunx, or pipx.
These launchers resolve code from package registries at runtime, introducing supply-chain risks if not properly pinned. If any non-waived floating launcher is detected, the action can hard-fail the job when fail-on-unpinned-autoexec is set to "true". This check executes always, regardless of Anthropic authentication availability, and emits results via the pin-scanned and pin-failed JSON outputs.
Claude Policy Scan (Requires Anthropic Auth)
When an anthropic-api-key or Workload Identity Federation (WIF) credentials are supplied, the action proceeds to the second stage defined at lines 65-82 of action.yml. This step installs the @anthropic-ai/claude-code CLI and executes scripts/scan.sh to evaluate each plugin against a customizable policy-prompt.
The CLI returns a structured verdict (passes: true/false) for each plugin, with findings reported as inline GitHub annotations and step summaries. The final aggregate result—either pass or fail—is exposed through the result output, while individual scan data flows through scanned and failed outputs.
Key Configuration Inputs
The action accepts several parameters that control authentication behavior and failure modes:
anthropic-api-keyoranthropic-federation-rule-id– Provide either a static API key or WIF configuration (plus organization and service-account details) to enable the Claude policy scan. If neither is provided, the scan stage skips gracefully while static checks continue (see lines 16-30 ofaction.yml).fail-on-findings– When set to"true", any policy violation causes the job to fail. By default, the action only annotates without failing.fail-on-unpinned-autoexec– Forces job termination if floating launchers are detected, preventing expensive Claude scans when basic security requirements fail.policy-prompt– Path to a custom markdown file containing the evaluation criteria Claude uses to judge plugin compliance.allowed-hosts– Comma-separated allow-list of git hosts permitted for cloning, acting as an SSRF guard during repository analysis.marketplace-path– Location of the plugin registry file (typically.claude-plugin/marketplace.json).
Outputs and Machine-Readable Results
The action generates five JSON outputs defined in action.yml (lines 84-114), enabling downstream automation and dashboard integration:
pin-scanned– Array of plugins analyzed during the static check phase.pin-failed– Array of plugins containing unwaived floating launchers.scanned– Detailed results from the Claude policy evaluation.failed– Specific policy violations detected by the AI scan.result– Aggregate verdict (passorfail) suitable for gating merge requirements.
All cloning and analysis operations execute at the pinned SHA, ensuring deterministic runtime behavior regardless of upstream repository changes.
Integration Examples
Basic Workflow with Full Scanning
Configure your repository to validate plugins on pull requests targeting the plugin registry:
name: Validate Plugins
on:
pull_request:
paths:
- '.claude-plugin/**'
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Scan Plugins
uses: ./.github/actions/scan-plugins
with:
anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
marketplace-path: .claude-plugin/marketplace.json
fail-on-findings: "true"
fail-on-unpinned-autoexec: "true"
Consuming JSON Results in Subsequent Steps
Access the structured outputs for custom reporting or conditional logic:
- name: Scan Plugins
id: scan
uses: ./.github/actions/scan-plugins
with:
anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
- name: Process Results
run: |
echo "Overall status: ${{ steps.scan.outputs.result }}"
echo "Detailed violations:"
echo '${{ steps.scan.outputs.scanned }}' | jq '.[] | select(.passes == false)'
Auth-Free Static Analysis Only
Run security checks without Anthropic credentials for cost-sensitive or public fork scenarios:
- name: Static Security Check
uses: ./.github/actions/scan-plugins
with:
marketplace-path: .claude-plugin/marketplace.json
fail-on-unpinned-autoexec: "true"
# No API key supplied; Claude scan is automatically skipped
Core Implementation Files
Understanding the file structure helps customize or debug the action:
.github/actions/scan-plugins/action.yml– Composite action definition containing inputs, outputs, and the ordered step sequence (setup, static pin check, WIF token minting, Node/CLI installation, and main scan invocation).scripts/static-pin-check.sh– Bash script performing the auth-free launcher analysis and generatingpin-scanned/pin-faileddata.scripts/scan.sh– Orchestration script that invokes the Claude CLI against the policy prompt and formats GitHub annotations..github/workflows/validate-plugins.yml– Reference implementation demonstrating production usage patterns.
Summary
- The scan-plugins composite GitHub Action combines static analysis and AI policy verification to secure Claude plugin contributions.
- Static pin checks run without authentication, detecting floating launchers like
npxandpipxthat could introduce runtime supply-chain risks. - Claude policy scans require Anthropic API keys or WIF credentials to evaluate plugins against customizable markdown prompts.
- Deterministic execution ensures all repository analysis occurs at pinned SHAs, preventing upstream tampering during CI execution.
- Rich JSON outputs (
pin-scanned,pin-failed,scanned,failed,result) enable integration with security dashboards and automated gating workflows.
Frequently Asked Questions
What happens if I don't provide an Anthropic API key?
The action gracefully degrades to static analysis only. According to the source code in action.yml (lines 16-30), when neither anthropic-api-key nor anthropic-federation-rule-id is present, the Claude policy scan stage skips entirely while the static pin check continues to execute. This ensures you can validate basic security requirements on public forks or cost-constrained environments without incurring API charges.
How does the action prevent supply-chain attacks via package managers?
The scripts/static-pin-check.sh component specifically hunts for floating launchers—commands like npx, uvx, bunx, and pipx that download and execute code from remote registries at runtime. By failing when fail-on-unpinned-autoexec is enabled, the action forces contributors to pin exact versions or use waivers, eliminating non-deterministic execution paths before they reach production.
Can I customize the security policies that Claude uses for evaluation?
Yes. The policy-prompt input accepts a file path to a custom markdown document. When provided, the action passes this content to the Claude CLI via scripts/scan.sh, allowing repository maintainers to define specific compliance rules regarding data handling, network access, or code quality standards beyond the default security baseline.
What is the difference between fail-on-findings and fail-on-unpinned-autoexec?
fail-on-unpinned-autoexec triggers failure during the static analysis phase when floating launchers are detected, stopping the pipeline before expensive AI scanning begins. fail-on-findings controls behavior during the Claude policy scan, causing the job to fail when the AI detects violations of the configured policy prompt. You can enable both for defense-in-depth or use them independently based on your risk tolerance.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →