Claude Plugin Security Review: 11 Policy Invariants and CI Validation Workflow

The Claude plugin security review enforces 11 strict static invariants (I1–I11) through the validate-plugins GitHub Action, validating structural integrity, preventing command injection, and pinning external dependencies to specific Git commits without executing untrusted code.

When submitting a plugin to the anthropics/claude-plugins-community repository, every pull request undergoes an automated Claude plugin security review that exceeds standard marketplace schema validation. The CI pipeline runs the validate-plugins action to block supply-chain attacks, enforce cryptographic provenance, and ensure metadata integrity before any code reaches users.

The 11 Security Invariants (I1–I11)

The core of the review is defined in .github/actions/validate-plugins/README.md, which mandates eleven static invariants stricter than the canonical Claude plugin schema:

  • I1: Alphabetical Ordering – The plugins[] array must be sorted alphabetically by the name field to ensure deterministic builds and prevent merge conflicts.

  • I2: Uniqueness – No duplicate name values are permitted within the marketplace catalog.

  • I3: Description Hygiene – The description field must contain 10–2000 characters with no leading or trailing whitespace.

  • I4: Source URL Safety – The source.url or source.repo must match a strict safe URL pattern—either an HTTPS URL or a valid owner/repo shorthand—preventing arbitrary protocol handlers.

  • I5: Cryptographic Pinning – Every external source must provide a 40-character lowercase hexadecimal SHA commit hash, ensuring immutable, auditable dependencies.

  • I6: Filename Consistency – For per-file plugin repositories, the JSON filename must match the plugin’s name field (e.g., plugins/my-plugin.json must declare "name": "my-plugin").

  • I7: Generated File Protection – Pull requests cannot manually edit the assembled marketplace.json file, as it is auto-generated during the CI process.

  • I8: Vendored Path Validation – Vendored source paths must exist and contain a valid .claude-plugin/plugin.json manifest file.

  • I9: Shell Metacharacter Sanitization – All string fields under source must be free of shell metacharacters to mitigate command injection risks during CI execution.

  • I10: Unicode Homoglyph Prevention – The name and description fields must contain no hidden Unicode characters such as zero-width spaces, byte-order marks (BOM), or bidirectional (bidi) control characters that could spoof plugin identities.

  • I11: Strict Naming Convention – The name must match the regex ^[a-z0-9][a-z0-9-]{1,63}$, restricting identifiers to lowercase alphanumerics and hyphens only.

Multi-Stage Security Model Workflow

Beyond the static invariants, the validation workflow implements a defense-in-depth strategy through sequential steps defined in the same README:

This architecture ensures that external code is never executed during the review process—only statically analyzed at a specific, immutable Git commit.

Critical Implementation Files

The Claude plugin security review is implemented across several key files in the repository:

Code Examples for Plugin Submission

The following examples demonstrate how to satisfy the security invariants and integrate validation into your workflow.

Minimal Compliant plugin.json

This manifest satisfies invariants I3, I4, I5, and I11:

{
  "name": "my-plugin",
  "description": "A short description (>=10 chars, <2000).",
  "source": {
    "url": "https://github.com/your-org/my-plugin",
    "sha": "0123456789abcdef0123456789abcdef01234567"
  }
}

GitHub Actions Workflow Integration

Add this workflow to .github/workflows/validate-plugins.yml to run the security review on pull requests:

name: Validate Plugins
on:
  pull_request:
    paths:
      - '.claude-plugin/**'
      - 'plugins/**'
      - '*/.claude-plugin/**'
      - '*/agents/**'
      - '*/skills/**'
      - '*/commands/**'

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

Local Validation Debugging

Run the validator locally to identify specific invariant failures before submitting:

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
export ALLOWED_HOSTS="github.com gitlab.com bitbucket.org"
mkdir -p "$VALIDATE_TMP"

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

Summary

  • The Claude plugin security review enforces 11 mandatory invariants (I1–I11) that restrict metadata format, Unicode content, and source provenance.
  • The validate-plugins action performs static analysis only, never executing external plugin code during validation.
  • All external dependencies must be pinned to a 40-character hexadecimal SHA to prevent supply-chain attacks.
  • The review checks for shell metacharacters and hidden Unicode to block injection and homoglyph attacks.
  • Validation occurs across five sequential steps, from invariant checking to auxiliary file parsing.

Frequently Asked Questions

What happens if my plugin fails the I10 Unicode check?

The I10 invariant rejects any name or description containing zero-width spaces, byte-order marks (BOM), or bidirectional text controls. Remove these invisible characters using a text editor that displays whitespace or run cat -v on your JSON file to identify hidden symbols.

Can I use a Git tag instead of a commit SHA for my plugin source?

No. The I5 invariant strictly requires a 40-character lowercase hexadecimal SHA. Tags are mutable and therefore rejected to ensure immutable, auditable dependencies according to the anthropics/claude-plugins-community security model.

Why can't I edit marketplace.json directly in my PR?

I7 prohibits manual edits to marketplace.json because it is a generated artifact. The file is assembled automatically by the CI pipeline from individual plugin definitions in the plugins/ directory or .claude-plugin/ subdirectories.

Does the security review execute my plugin code to test it?

No. As implemented in scripts/30-validate-cli-external.sh, the validator clones your repository at the pinned SHA and validates the plugin.json manifest only. No build steps, installation, or code execution occurs during the review process.

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 →