What Fields Are Evaluated by the Security Scanning Policy for Claude Plugins
The security scanning policy inspects the .source object of each plugin entry, specifically validating url/repo fields, enforcing 40‑character hex SHA requirements, scanning every string value for shell metacharacters, and verifying vendored filesystem paths.
The anthropics/claude-plugins-community repository enforces strict supply‑chain controls through the validate‑plugins GitHub Action. This automated security scanning policy concentrates its checks on the .source object within marketplace.json entries to mitigate injection attacks and guarantee repository integrity.
The .source Object: Primary Evaluation Target
According to the source code in .github/actions/validate-plugins/scripts/11-validate-invariants.sh, the validation layer "enforces security policy on whichever fields are present" inside the .source object (lines 24‑25). The policy applies four specific invariants—I4, I5, I8, and I9—that govern remote URLs, commit identifiers, string sanitization, and local directory structure.
URL and Repository Format (Invariant I4)
I4 evaluates the source.url or source.repo field to ensure it references a trustworthy remote location. The check accepts either:
- A safe HTTPS URL, or
- A GitHub‑style
owner/reposhorthand matching the pattern^[A-Za-z0-9][A-Za-z0-9_.-]*/[A-Za-z0-9][A-Za-z0-9_.-]*$
Any protocol other than HTTPS (such as HTTP or Git) triggers a validation failure.
Commit SHA Validation (Invariant I5)
I5 mandates that source.sha contain a full Git commit hash. The invariant requires exactly 40 hexadecimal characters (^[0-9a-f]{40}$). The script allows specific entries to omit the SHA only if they appear in a designated SHA_EXEMPT list; otherwise, a missing or malformed hash produces an error.
Shell Character Sanitization (Invariant I9)
I9 performs a defensive sweep across every string‑valued field nested under .source, including url, repo, sha, and path. Using a has_unsafe_chars helper, the scanner detects metacharacters such as &, |, ;, <, and >. If any field contains these symbols, the policy flags a security violation to prevent command‑injection exploits.
Vendored Path Integrity (Invariant I8)
When .source points to a local vendored path rather than a remote URL, I8 validates the filesystem location. The check verifies that the directory exists and contains a .claude-plugin/plugin.json file, ensuring bundled plugins are complete and correctly structured before acceptance.
Implementation in the Validation Script
The security logic resides in .github/actions/validate-plugins/scripts/11-validate-invariants.sh. Lines 26‑57 implement the loops for I4, I5, and I9, extracting the url, sha, and iterating over all string values under .source. Lines 72‑84 handle I8, confirming the existence of vendored directories and their metadata files.
Compliance Examples
A minimal configuration that satisfies all invariants:
{
"name": "example-plugin",
"description": "A short description.",
"source": {
"url": "https://github.com/example/example-plugin",
"sha": "d3b07384d113edec49eaa6238ad5ff00a6c5b7be"
}
}
An invalid entry that triggers I4, I5, and I9 violations:
{
"name": "bad-plugin",
"description": "Bad source example.",
"source": {
"url": "http://insecure.example.com|rm -rf /",
"sha": "12345"
}
}
Running the validation action on the second example emits errors resembling:
::error file=.../marketplace.json:invariant I4: bad-plugin: source url/repo is not a safe https URL or owner/repo shorthand: http://insecure.example.com|rm -rf /
::error file=.../marketplace.json:invariant I5: bad-plugin: source.sha is missing or not a 40-char hex SHA
::error file=.../marketplace.json:invariant I9: bad-plugin: source field contains shell metacharacters: http://insecure.example.com|rm -rf /
Summary
- The security scanning policy targets the
.sourceobject of each plugin entry inmarketplace.json. - I4 enforces HTTPS or strict
owner/repoformatting for remote sources. - I5 requires a valid 40‑character hexadecimal SHA; exemptions are granted only via
SHA_EXEMPT. - I9 scans all string fields under
.sourcefor unsafe shell characters usinghas_unsafe_chars. - I8 validates local vendored paths for required
.claude-plugin/plugin.jsonmetadata. - All checks execute within
.github/actions/validate-plugins/scripts/11-validate-invariants.shas part of the validate‑plugins GitHub Action.
Frequently Asked Questions
Does the security scanning policy evaluate fields outside the .source object?
While the repository defines eleven total invariants (I1 through I11) that check name length, description size, and schema validity, the specific security‑focused checks (I4, I5, I8, I9) exclusively inspect fields within the .source object. These constraints prevent arbitrary code execution and ensure supply‑chain provenance.
What happens if a plugin uses an HTTP URL instead of HTTPS?
The I4 invariant rejects any source.url that does not use the HTTPS protocol. The validation script explicitly checks for safe HTTPS URLs or GitHub owner/repo shorthands, flagging plain HTTP as a security violation to prevent man‑in‑the‑middle attacks.
Are SHA hashes optional for community plugins?
I5 generally mandates a 40‑character hex SHA for every plugin entry. However, the policy allows specific exceptions through the SHA_EXEMPT list. If an entry is not exempt and lacks a valid SHA, the validation action fails, blocking the submission from the marketplace.
How does the policy prevent command injection vulnerabilities?
I9 mitigates injection risks by scanning every string value inside .source for shell metacharacters such as &, |, ;, <, and >. The script utilizes a has_unsafe_chars function to detect these symbols; if found, the validator emits an error and halts processing, ensuring malicious payloads cannot reach the build pipeline.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →