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

> Discover the 11 policy invariants checked during the Claude plugin security review. Learn how CI validation prevents command injection and secures dependencies without executing untrusted code.

- Repository: [Anthropic/claude-plugins-community](https://github.com/anthropics/claude-plugins-community)
- Tags: best-practices
- Published: 2026-08-31

---

**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`](https://github.com/anthropics/claude-plugins-community/blob/main/.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`](https://github.com/anthropics/claude-plugins-community/blob/main/plugins/my-plugin.json) must declare `"name": "my-plugin"`).

- **I7: Generated File Protection** – Pull requests cannot manually edit the assembled [`marketplace.json`](https://github.com/anthropics/claude-plugins-community/blob/main/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`](https://github.com/anthropics/claude-plugins-community/blob/main/.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:

- **Step 11** – Executes [`scripts/11-validate-invariants.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/scripts/11-validate-invariants.sh) to verify I1–I11 against the full marketplace dataset.

- **Step 20** – Runs `claude plugin validate` via [`scripts/20-validate-cli-marketplace.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/scripts/20-validate-cli-marketplace.sh) to check canonical schema compliance.

- **Step 30** – Clones each external plugin at its pinned SHA using [`scripts/30-validate-cli-external.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/scripts/30-validate-cli-external.sh), validating manifests without executing plugin code.

- **Step 40** – Uses [`scripts/40-validate-cli-local.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/scripts/40-validate-cli-local.sh) to validate in-repository plugins modified in the current PR.

- **Step 41** – Parses auxiliary configuration files ([`.mcp.json`](https://github.com/anthropics/claude-plugins-community/blob/main/.mcp.json), [`.lsp.json`](https://github.com/anthropics/claude-plugins-community/blob/main/.lsp.json), [`hooks.json`](https://github.com/anthropics/claude-plugins-community/blob/main/hooks.json)) through [`scripts/41-validate-aux-files.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/scripts/41-validate-aux-files.sh) to ensure runtime safety.

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:

- [`.github/actions/validate-plugins/README.md`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/validate-plugins/README.md) – Documents the I1–I11 invariants and security model.
- [`.github/actions/validate-plugins/scripts/11-validate-invariants.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/validate-plugins/scripts/11-validate-invariants.sh) – Enforces the eleven static policy checks.
- [`.github/actions/validate-plugins/scripts/20-validate-cli-marketplace.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/validate-plugins/scripts/20-validate-cli-marketplace.sh) – Validates against the official Claude CLI schema.
- [`.github/actions/validate-plugins/scripts/30-validate-cli-external.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/validate-plugins/scripts/30-validate-cli-external.sh) – Safely clones and validates external plugins at pinned commits.
- [`.github/actions/validate-plugins/scripts/40-validate-cli-local.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/validate-plugins/scripts/40-validate-cli-local.sh) – Handles in-repo plugin validation.
- [`.github/actions/validate-plugins/scripts/41-validate-aux-files.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/validate-plugins/scripts/41-validate-aux-files.sh) – Parses auxiliary JSON files.
- [`.github/policy/prompt.md`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/policy/prompt.md) – Contains the broader Anthropic Software Directory Policy referenced during security scans.

## 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:

```json
{
  "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`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/workflows/validate-plugins.yml) to run the security review on pull requests:

```yaml
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:

```bash
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`](https://github.com/anthropics/claude-plugins-community/blob/main/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`](https://github.com/anthropics/claude-plugins-community/blob/main/scripts/30-validate-cli-external.sh), the validator clones your repository at the pinned SHA and validates the [`plugin.json`](https://github.com/anthropics/claude-plugins-community/blob/main/plugin.json) manifest only. No build steps, installation, or code execution occurs during the review process.