Check M6 · execution surface family · severity MEDIUM · automatic · one of the 10 MCP-server checks
Maps to OWASP LLM03 ATLAS AML.T0010 A package launched at whatever version is newest runs the next release unseen, which is how a takeover reaches every user at once.
The question this check asks: when your client starts this server tomorrow, will it run the same code it runs today?
A package launched at whatever version is newest runs the next release unseen. That is how a hijacked maintainer account reaches every user of a package at once: nothing on the user's side changes, and the next start runs the new code.
Every package the listing declares is read. A package with no version, or latest, is mcpr-unpinned:<package>, MEDIUM and 4 points. An OCI image counts as pinned by a digest or a tag other than latest. An MCPB bundle is pinned only by a well-formed SHA-256 (64 hexadecimal characters) in the listing. A bundle named by the URL of a release asset on github.com fixes a tag, which its owner can move or re-upload under: that is a note, mcpr-tag-pinned:<bundle>. Any other bundle URL, or a SHA-256 that is not well formed, is the MEDIUM unpinned finding. A warning under the default profile, never a block on its own.
A vendor that publishes its bundle as a GitHub release asset without a SHA-256 gets a note, not a finding; the note says why it is less than a digest.
What the next version contains. Whether a pinned version is itself sound; that is M4's question. The version your own configuration pins: this reads the listing, not your client's settings.
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. On a claude mcp add line, a remote address that a listed server declares is judged with that listing's verdict riding along, and is still an ask: anyone may declare any address in a listing, and the server answering there runs on its operator's machine. A listing whose verdict is BLOCK is denied. An address no listed server declares is asked about. A server added by editing a configuration file or through /mcp is not a shell line the hook sees. Edit and Write are read for one thing only — an API key about to be saved — checked on the machine and never sent; that guard asks, it never denies. This roster reads what the official MCP registry publishes about a server — its record, its version history, the repository and packages it declares, the remote addresses it names — and never the server's code or what it does once it runs. A remote-only server is REVIEW at best, never a pass. The registry carries no download count, star count or popularity of any kind, so there is no lookalike check. A server the registry no longer serves is not assessed, never a pass. A PASS means nothing matched on what was read.
curl -s "https://registry.modelcontextprotocol.io/v0/servers/NAMESPACE%2FNAME/versions/latest" | jq '[.server.packages[]? | {registryType, identifier, version, fileSha256}]'
What counts as pinned? An npm or PyPI package with a version other than latest; an OCI image with a digest or a tag other than latest; an MCPB bundle with a well-formed SHA-256 in the listing.
Why is a GitHub release asset only a note? Its URL fixes a tag, and the repository's owner can move the tag or re-upload the asset under it. It is better than nothing and less than a digest, so it is recorded as a note.
Does this check read my MCP configuration? No. It reads the registry listing. A version you pin yourself in your client's configuration is not seen.
M4 Launched package · M8 Launch arguments · S12 Marketplace source pinning.
Add RepoGates to Chrome Pricing
Sources for this page: the severities and weights from the product's own roster and scoring tables, and the official MCP registry's published record format. See also the MCP servers intelligence page.