Check S12 · execution surface family · severity HIGH · automatic · one of the 15 skill and plugin checks
The question this check asks: when Claude Code installs this plugin, what exactly does it fetch — and is that fixed? A marketplace entry's source names a place. A pin names a commit. The gap between the two is what someone else can change after the catalogue was written. S12 runs on plugin keys only, skill/plugin/{owner}/{repo}/{plugin}: a skills.sh skill has no marketplace entry, and a ClawHub skill is never a plugin.
The clearest statement of what a pin is for was written by someone looking for the hole. John Stawinski IV's post of 18 June 2026 on Anthropic's community marketplace found five entries pointing at GitHub owners that had been renamed or deleted — mailfnguides-del/Claude-Paste, comment-io/claude-code-plugin, CharlieGreenman/ghostlty-dynamic-themes, Chipkorvyn/Strategy-consultant, oduffy-delphi/deep-research-claude — names anyone could register again with a repository of the same name. Each was pinned to a commit sha, and, in his words, “a recreated repository … cannot reproduce the pinned commit with any modified content”. No plugin was compromised; he registered one of the names only as proof. Reported on 25 May, the report was closed the same day as “Informative, out of scope”. The pin was the whole defence in that story. This check reads whether it is there.
The second reason is what the other source forms do at install. Claude Code's plugin documentation gives a marketplace entry seven shapes: a relative path into the marketplace repository, and six object sources — github, url, git-subdir, npm, archive and command. A command source produces the plugin directory by running a command on the user's machine — at install, and again once per session; the documentation binds every run to the user's explicit acceptance, and gives administrators disableCommandPluginSources to refuse the kind across an organisation. An archive is verified only when the entry carries a sha256: a mismatch fails with “Plugin archive integrity check failed”, and archives over 256 MiB are refused. A git source without a sha installs whatever the branch holds today. The malicious skills page keeps the report and the measurement.
S12 reads the marketplace catalogue whole — never through the 64 KB per-file cap — finds the entry by name, and classifies its source. A relative path (./plugins/x) is the marketplace repository itself, pinned by the commit the catalogue was read at: nothing to note. A github {repo, ref?, sha?}, url {url, ref?, sha?} or git-subdir {url, path, ref?, sha?} source is pinned when sha is a 40-hex commit — the documentation's own rule, “When both ref and sha are set … the sha is the effective pin”. Without one, skill-plugin-source:unpinned: MEDIUM, 6 points, warn, reading “a github source with no commit sha — the marketplace catalogues pin one; an unpinned entry installs whatever the branch holds”. A git host other than github.com adds skill-plugin-source:external:<host> at 0 points: a source this tier does not read. An archive {url, sha256?} with no checksum is skill-plugin-source:archive-unverified, MEDIUM, 6 points, warn — “what is fetched is whatever the URL serves today”. An npm source is skill-plugin-source:npm at 0 points: the registry's tree, not a repository this tier reads. And a command source is skill-plugin-source:command: HIGH, 15 points, warn — “the marketplace installs this plugin by running a command through the shell — at install and once per session”.
HIGH is this check's ceiling, so its worst outcome is a REVIEW, warned: the install is held, the shape is named, and proceeding is one recorded click. It never blocks on its own. What the resolved source contains is S1's question — the 22 checks run on the repository the pin names — and what its hooks and servers do at session time is S13's and S14's.
Measured on 20 September 2026 through the same code as /v1/skill/score: the official catalogue pins 258 of its 258 object sources and the community catalogue 2,274 of 2,277, and across all 310 official-marketplace plugins and the first 100 community plugins this check fired nothing above INFO. The five repositories from the June report are present today, sha-pinned, and S12 is silent on each — as it should be, since the pin is what the check asks for. The fixture that reconstructs the other case, a catalogue with a command source and an unpinned github source, is REVIEW or worse under the default profile.
An unpinned source under a marketplace that pins as policy. Three of the community catalogue's 2,277 object sources carry no sha; the row names the shape, the marketplace's README says every plugin is pinned, and an override records the reason. The finding is true either way — those three install whatever their branch holds.
A command source that is exactly what the documentation describes: “Plugin directory produced by running a local command, re-run once per session to pick up changes” — a build step, a generator. Claude Code binds it to the user's acceptance whether or not RepoGates is present. S12 says that this plugin is a command; it does not read what the command does, and the text of the command is not graded on this tier. A REVIEW here is a description.
A gh key. A skills.sh skill has no marketplace entry, so there is no source to classify and nothing to pin; which repository it is, and what the 22 checks make of it, is S1. What the pinned commit contains — the source's own provenance is S1, its text is the instruction and script checks, its hooks and servers S13 and S14. Whether the pin still holds tomorrow. The catalogue is read at scan time; a marketplace that later edits an entry is a new scan. The user's own marketplace policy. strictKnownMarketplaces and blockedMarketplaces are enforced by Claude Code on install, update, refresh and autoupdate; they are settings on the user's machine, and nothing here reads them. ClawHub (@owner/slug) is parsed and routed but not assessed on this tier: a ClawHub skill is never a plugin, so this check has nothing to run there, and a ClawHub key as a whole answers “not assessed” — never a pass.
Scope, the same on every page of this roster: RepoGates does not see git clone, package managers or curl — outside Claude Code with the RepoGates plugin, whose hook refuses a clone or install that names a blocked repository on the command line, before it runs. The hook sees Bash tool calls in that one client and nothing else: npx skills add owner/repo and claude plugin install name@marketplace are shell lines it judges; /plugin install is a slash command the hook never sees; a skill copied by hand into ~/.claude/skills is never seen at all. This tier reads the listing record, the tree once, and at most twelve files of 64 KB each — SKILL.md files first, then a plugin's agents and commands, then the scripts beside each skill; more than fits is a partial scan, stated, and never a pass on what was not read. The deep scan reads the whole package. A PASS means nothing matched on what was read, never that the skill was run.
Open the catalogue and read the entry's source:
curl -s https://raw.githubusercontent.com/anthropics/claude-plugins-official/main/.claude-plugin/marketplace.json \
| jq '.plugins[] | select(.name=="PLUGIN") | .source'
A string starting ./ is the marketplace repository itself. An object names its kind in source; look for a 40-character sha on a git source, a sha256 on an archive, and a command field at all. To see every entry that lacks a pin in one pass:
jq -r '.plugins[] | select(.source|type=="object")
| select(.source.source|IN("github","url","git-subdir"))
| select(.source.sha==null) | .name' marketplace.json
Then confirm the pinned commit exists in the repository the entry names — git ls-remote against it — and that the owner is still the owner. A name that resolves to a different account than the one that wrote the entry is the June report's shape, and the pin is what keeps it a curiosity.
What does a commit sha actually protect against? A source that has changed hands. John Stawinski's 18 June 2026 post found five community-marketplace entries whose GitHub owners had been renamed or deleted — names anyone could register again, with a repository of the same name and files. Each entry was pinned to a commit sha, and a recreated repository cannot reproduce the pinned commit with any modified content, so the install refuses what the new owner serves. No plugin was compromised. That is the whole of what the pin does: it fixes what is fetched to one commit's content, whoever holds the name today. Without it, a github, url or git-subdir source installs whatever the branch holds at the moment of install, and S12 says so.
Why is a command source a warning and not a block? Because Claude Code already treats it as what it is. A command source produces the plugin directory by running a command on the user's machine, at install and again once per session, and the documentation binds every run to the user's explicit acceptance — an interactive prompt, --yes, or --accept-command with the command's sha256 since 2.1.271 — and gives administrators disableCommandPluginSources to refuse the kind outright. S12 grades the shape HIGH and warns, so the reader sees that this plugin is a command before the acceptance prompt does; what the command does is not graded on this tier. A REVIEW on this row is an accurate description, not an accusation.
Does this check run on a skills.sh skill? No. Only a plugin key carries a marketplace entry, and the entry's source is what S12 reads. A skills.sh skill is a directory in a GitHub repository, installed by npx skills add owner/repo from that repository's tree — there is no catalogue in between and nothing to pin; which repository it is, and what the 22 checks make of it, is S1. A ClawHub skill is never a plugin, so a ClawHub key gives this check nothing to run either — and ClawHub is parsed and routed but not assessed on this tier as a whole.
S1 Source repository — the repository the pin names, assessed through the 22 checks on the same pass · S13 Hooks and monitors — what the installed plugin runs at session time without the agent deciding · S14 MCP servers — the servers the installed plugin launches, and how.
Add RepoGates to Chrome Pricing
Numbers on this page: the 20 September 2026 measurement of all 310 official-marketplace plugins and the first 100 community-marketplace plugins, and the pin counts of both catalogues (258 of 258; 2,274 of 2,277), run through the same code as /v1/skill/score; Claude Code's plugin and marketplace documentation as read on that date; John Stawinski IV's report of 18 June 2026, in the record behind the malicious skills page; thresholds and weights from the product's policy and scoring tables.