How the Claude Plugin Marketplace Validation and Security Scanning Process Works

The Claude plugin marketplace employs a fully automated CI pipeline via the validate-plugins composite GitHub Action that enforces strict schema compliance and security invariants through seven distinct validation stages, including change detection, invariant hardening, canonical schema validation, and isolated external plugin verification.

The anthropics/claude-plugins-community repository maintains a robust validation framework to ensure every plugin entry meets security and structural standards before publication. This Claude plugin marketplace validation system operates as a composite GitHub Action that orchestrates multiple shell scripts to detect changes, enforce invariants, and validate both local and external plugin manifests against the official Claude SDK schema.

The Seven-Stage Validation Pipeline

The validation process executes sequentially through specialized shell scripts located in .github/actions/validate-plugins/scripts/. Each stage performs distinct checks to guarantee marketplace integrity.

1. Change Detection with 00-detect-changes.sh

The pipeline begins by identifying which plugins were added, removed, or modified in the pull request. The 00-detect-changes.sh script builds a scoped list of changed entries, ensuring that historic defects in unchanged plugins do not block new contributions. This scoped list drives the scope-errors-to-changed functionality, which downgrades violations in untouched entries from errors to warnings.

2. Invariant Hardening via 11-validate-invariants.sh

The 11-validate-invariants.sh script enforces eleven custom rules (I1–I11) on the full marketplace.json file. These invariants prevent common security and structural issues:

  • I1–I2: Enforce global alphabetical ordering and uniqueness of plugin names.
  • I3–I5: Validate description length constraints, enforce HTTPS-only URLs, and require a 40-character SHA-256 pin for every external source (with an optional exemption list).
  • I6–I7: In per-file repositories, verify that each file name matches the internal .name field and prevent direct editing of the assembled marketplace.json.
  • I8: Confirm that vendored source paths contain a .claude-plugin/plugin.json file.
  • I9: Scan all string fields under source for shell-metacharacters to prevent command injection attacks.
  • I10: Disallow hidden Unicode characters (zero-width spaces, bidirectional overrides, BOM) in names and descriptions.
  • I11: Validate that plugin names match the regex ^[a-z0-9][a-z0-9-]{1,63}$.

Violations report as errors or warnings, with the latter optionally promoted to failures via the fail-on-warnings input parameter.

3. Canonical Schema Validation

The action installs the latest @anthropic-ai/claude-code package and executes claude plugin validate <marketplace.json> against the current JSON. This step validates the marketplace against the up-to-date Zod schema defined in the official Claude SDK, eliminating schema drift by removing the need for vendored JSON schemas within the repository.

4. External Plugin Security Scanning

For plugins referencing external repositories, the 30-validate-cli-external.sh script implements a hardened verification process:

  • Host Allowlisting: Validates URLs against an allowlist containing github.com, gitlab.com, and bitbucket.org to block SSRF attacks.
  • Immutable Checkout: Clones the external repository into an isolated temporary directory and checks out the exact pinned SHA-256 commit.
  • Static Validation Only: Executes claude plugin validate against the external plugin.json without executing any code from the cloned repository.
  • Synthetic Manifest Generation: For entries marked strict:false that lack a plugin.json, the pipeline generates a minimal synthetic manifest using jq and validates it.

This design ensures that malicious external repositories cannot execute arbitrary code during the CI process.

5. Local Plugin Validation

The 40-validate-cli-local.sh script validates all in-repository plugin folders touched by the PR using the same claude plugin validate command, ensuring local modifications meet identical standards to external entries.

6. Auxiliary Files Parsing

The 41-validate-aux-files.sh script parses supplementary configuration files—including .mcp.json, .lsp.json, and hooks/hooks.json—to confirm they are well-formed JSON. Malformed auxiliary files trigger immediate workflow failures to prevent runtime crashes.

7. Reporting and Status Determination

Finally, 90-report.sh generates a comprehensive markdown report summarizing errors, warnings, changed entries, external plugins, and validated folders. The script sets the job output result to pass or fail based on the accumulated validation state.

Security Guarantees and Attack Mitigations

The validation pipeline implements multiple defensive layers to protect against supply chain attacks and injection vulnerabilities.

Immutable SHA Pinning Requirements

External plugins must reference an immutable 40-character SHA-256 commit hash. The workflow rejects any entry lacking a valid SHA unless explicitly exempted, ensuring that plugin code cannot change unexpectedly after listing approval.

SSRF Protection Through Host Allowlisting

The system validates all external URLs against a strict hostname allowlist. Any URL pointing to an IP address or unapproved domain aborts the clone operation, preventing Server-Side Request Forgery attacks.

Shell Injection Defenses

The 11-validate-invariants.sh script scans source fields for dangerous characters using an has_unsafe_chars helper. All values interpolated into shell commands are double-quoted and protected by -- end-of-options flags, eliminating command injection vectors.

Temporary Directory Isolation

Cloned external repositories exist only within temporary directories that are deleted immediately after validation. This guarantees no persistent side-effects or cache poisoning between workflow runs.

Running the Validator Locally

Developers can execute the validation pipeline locally to debug issues before submitting pull requests:


# Configure environment variables

export ACTION_PATH=.github/actions/validate-plugins
export VALIDATE_TMP=/tmp/validate-plugins
export BASE_REF=origin/main
export MARKETPLACE_PATH=.claude-plugin/marketplace.json

mkdir -p "$VALIDATE_TMP"

# Execute validation scripts sequentially

bash $ACTION_PATH/scripts/00-detect-changes.sh
bash $ACTION_PATH/scripts/11-validate-invariants.sh
bash $ACTION_PATH/scripts/20-validate-cli-marketplace.sh
bash $ACTION_PATH/scripts/30-validate-cli-external.sh
bash $ACTION_PATH/scripts/40-validate-cli-local.sh
bash $ACTION_PATH/scripts/41-validate-aux-files.sh
bash $ACTION_PATH/scripts/90-report.sh

For CI integration, reference the composite action in your workflow:

name: Validate Plugins
on:
  pull_request:
    paths:
      - '.claude-plugin/**'
      - '*/.claude-plugin/**'
jobs:
  validate:
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: anthropics/claude-plugins-community/.github/actions/validate-plugins@<PINNED-SHA>
        with:
          marketplace-path: .claude-plugin/marketplace.json

Key Implementation Files

Component Path Purpose
Composite Action definition .github/actions/validate-plugins/action.yml Orchestrates the validation steps
Design documentation .github/actions/validate-plugins/README.md Describes validation layers and security model
Change detection .github/actions/validate-plugins/scripts/00-detect-changes.sh Identifies modified plugins in PRs
Invariant checks .github/actions/validate-plugins/scripts/11-validate-invariants.sh Implements I1–I11 hardening rules
External validation .github/actions/validate-plugins/scripts/30-validate-cli-external.sh Clones and validates external repos at pinned SHAs
Report generation .github/actions/validate-plugins/scripts/90-report.sh Generates markdown summary and sets job outputs

Summary

  • The Claude plugin marketplace validation process runs as a composite GitHub Action executing seven specialized shell scripts in sequence.
  • Invariant hardening (I1–I11) enforces structural rules including SHA-256 pinning, Unicode sanitization, and shell-injection prevention.
  • Canonical schema validation uses the live @anthropic-ai/claude-code package to verify against the latest Zod schema without vendored drift.
  • External plugin validation operates under strict security constraints: host allowlisting, immutable SHA checkout, and static-only analysis with no code execution.
  • The scope-errors-to-changed feature prevents legacy defects from blocking clean pull requests by downgrading historical violations to warnings.

Frequently Asked Questions

What happens if a plugin violates the invariant rules?

Violations report as errors or warnings depending on severity. When scope-errors-to-changed is enabled, violations in untouched legacy entries downgrade to warnings, while new or modified plugins must pass all checks. Setting fail-on-warnings: true promotes all warnings to hard failures.

How does the system prevent malicious code from external repositories?

The validation pipeline never executes code from external repositories. It only performs static manifest validation using claude plugin validate. External repos clone into isolated temporary directories using strictly pinned SHAs, and hostnames are allowlisted to github.com, gitlab.com, and bitbucket.org to prevent SSRF attacks.

Can I run the validation locally before submitting a PR?

Yes. Export the required environment variables (ACTION_PATH, VALIDATE_TMP, BASE_REF, MARKETPLACE_PATH) and execute the shell scripts in .github/actions/validate-plugins/scripts/ sequentially, starting with 00-detect-changes.sh and ending with 90-report.sh.

What is the difference between strict and non-strict external plugins?

Entries marked strict:true must provide a valid plugin.json manifest in their repository. Entries with strict:false that lack a manifest file receive a synthetic manifest generated via jq containing minimal metadata, which is then validated against the schema. Both types require a pinned SHA-256 commit hash.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →