# Static Pin Check in scan-plugins: Preventing Supply Chain Attacks in Claude Plugins

> Discover the static pin check in scan-plugins, a crucial GitHub Action that prevents supply chain attacks by validating package specifications without network access. Secure your MCP server manifests.

- Repository: [Anthropic/claude-plugins-community](https://github.com/anthropics/claude-plugins-community)
- Tags: deep-dive
- Published: 2026-08-24

---

**The static pin check is a deterministic, network-free validation step in the `scan-plugins` GitHub Action that detects floating package specifications in MCP server manifests to prevent supply chain attacks.**

The `anthropics/claude-plugins-community` repository employs a rigorous security pipeline to validate community plugins. The **static pin check** serves as a critical safeguard within the `scan-plugins` action, ensuring that every external command declared in a plugin's manifest—whether using `npx`, `uvx`, `pipx`, or `bunx`—references an immutable, version-locked dependency rather than a mutable tag like `latest`.

## How the Static Pin Check Works

The static pin check operates as a **pure Bash and jq** analysis that requires **zero network access** to classify dependency specifications. When the `scan-plugins` action runs, it invokes [`scripts/static-pin-check.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/scripts/static-pin-check.sh), which loads the classification logic from [`lib/pin-check.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/lib/pin-check.sh) to audit each `mcpServers` entry in [`.mcp.json`](https://github.com/anthropics/claude-plugins-community/blob/main/.mcp.json) or [`plugin.json`](https://github.com/anthropics/claude-plugins-community/blob/main/plugin.json) manifests.

### Dependency Classification Logic

In [`lib/pin-check.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/lib/pin-check.sh), the analyzer categorizes each launcher specification into one of seven distinct states:

- **Pinned** – Exact version specified (e.g., `pkg@1.2.3`)
- **Floating** – Version ranges or mutable tags (e.g., `pkg@latest`, `pkg@^1.2`)
- **Bare** – Package name only without version
- **Vendored** – Local binaries bundled with the plugin
- **Local** – Absolute or relative paths to executables
- **VCSref** – Git commit SHA or tag references
- **None** – No external dependency declared

Any specification classified as **floating** or **bare-but-not-vendored** triggers an immediate policy violation warning.

### CI Integration and Execution

The entry point [`scripts/static-pin-check.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/scripts/static-pin-check.sh) orchestrates the validation by parsing manifests and emitting GitHub Actions annotation commands. This script is executed automatically by the workflow defined in [`.github/workflows/validate-plugins.yml`](https://github.com/anthropics/claude-plugins-community/blob/main/.github/workflows/validate-plugins.yml), ensuring every pull request undergoes automated pinning verification before merge.

## Why the Static Pin Check Is Critical

Unchecked floating dependencies create a **supply chain attack surface** where malicious actors can publish compromised package versions that execute automatically on user machines. Because the static pin check runs deterministically without external network calls, it guarantees that the code reviewed by Claude's policy systems matches exactly what executes in production.

- **Deterministic security**: Ensures runtime code matches the repository's source SHA reviewed by policy LLMs, preventing supply chain drift.
- **Zero-network guarantee**: The check executes entirely within the CI environment, making it impossible for malicious plugins to evade detection via external service calls.
- **Fail-safe design**: Parsing errors default to empty result sets rather than workflow crashes, maintaining CI stability when encountering malformed manifests.
- **Policy enforcement**: Integrates with the broader `scan-plugins` security layer (defined in [`action.yml`](https://github.com/anthropics/claude-plugins-community/blob/main/action.yml)) to block or warn on unsafe plugins before they reach downstream users.

## Running the Static Pin Check Locally

Developers can execute the same validation logic used in CI to verify their plugin manifests before submitting pull requests:

```bash

# Execute the static pin check from the repository root

ACTION_PATH=.github/actions/scan-plugins
"$ACTION_PATH/scripts/static-pin-check.sh"

```

When the detector identifies a floating specification, it outputs a GitHub Actions warning annotation:

```text
::warning scan-plugins: my-plugin.json — pkg@latest; pin-state not assessed

```

## Fixing Floating Dependency Violations

To resolve policy violations, convert floating or bare package references to pinned versions in your [`.mcp.json`](https://github.com/anthropics/claude-plugins-community/blob/main/.mcp.json) or [`plugin.json`](https://github.com/anthropics/claude-plugins-community/blob/main/plugin.json) manifest:

```json
{
  "mcpServers": [
    {
      "name": "my-runner",
      "command": "npx my-package@1.2.3"
    }
  ]
}

```

Replace mutable tags like `latest` or semver ranges like `^1.2.0` with explicit version strings (e.g., `1.2.3`) to achieve a compliant **pinned** classification.

## Summary

- The **static pin check** is a deterministic, network-free validation step in `anthropics/claude-plugins-community` that audits MCP server manifests in the `scan-plugins` action.
- It classifies dependencies into seven categories via [`lib/pin-check.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/lib/pin-check.sh), flagging **floating** and **bare-but-not-vendored** specifications as security risks.
- The check runs automatically via [`scripts/static-pin-check.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/scripts/static-pin-check.sh) in the CI pipeline defined in [`validate-plugins.yml`](https://github.com/anthropics/claude-plugins-community/blob/main/validate-plugins.yml).
- Version pinning prevents supply chain attacks by ensuring the exact code reviewed matches what executes at runtime.
- Developers can run the check locally and fix violations by specifying exact package versions in their plugin manifests.

## Frequently Asked Questions

### What triggers a static pin check failure?

A failure occurs when the analyzer detects **floating** dependencies (such as `pkg@latest` or version ranges like `pkg@^1.2`) or **bare** package names without explicit versions in the `mcpServers` command declarations. These specifications resolve dynamically at runtime, creating uncertainty about which code actually executes.

### Can I use `npx` or `pipx` without version pinning in my Claude plugin?

No. The `scan-plugins` action requires all external package runners—including `npx`, `pipx`, `uvx`, and `bunx`—to use **exact version pinning** (e.g., `package@2.1.0`). Commands without pinned versions violate the deterministic security policy designed to protect users from supply chain attacks.

### How does the static pin check work without network access?

The check uses **pure Bash and jq** parsing implemented in [`lib/pin-check.sh`](https://github.com/anthropics/claude-plugins-community/blob/main/lib/pin-check.sh) to analyze the text of command strings in your manifest. It classifies dependencies based solely on the syntax of the package specification (looking for version tags, SHA references, or local paths) rather than querying npm, PyPI, or other registries, ensuring the validation cannot be bypassed or influenced by external services.

### What should I do if my plugin uses a vendored local binary?

If your plugin bundles its own executable (vendored) or references an absolute path (local), the static pin check will classify these as **vendored** or **local** respectively. These classifications are considered safe and compliant, provided the binary is actually included in your repository or the path is correctly specified, as they do not rely on external package registries at runtime.