MCP-002 Mutable git ref
An MCP server entry installs from a git source (git+https://...,
https://github.com/..., or a uvx --from git+... pair) whose ref
is a moving branch (HEAD, main, master, trunk, develop,
dev) or is not pinned at all. Branches can be force-pushed, tags
can be silently retagged; only a commit SHA is immutable. Without a
SHA pin the next host launch can resolve to different code than the
one you reviewed.
What Vulkro detects
Rule fires when an mcpServers[*] entry has an argument that parses
as a git URL AND the ref portion is not an immutable SHA.
The detector recognises:
- npm convention
#<ref>:git+https://github.com/vendor/repo#main,git+https://github.com/vendor/repo#a1b2c3d4... - uvx / pip convention
@<ref>:git+https://github.com/vendor/repo@main,git+https://github.com/vendor/repo@a1b2c3d4... - The
uvx --from git+<url> <pkg>pair (the URL after--fromis inspected, the URL is not double-counted with an inline form). - No ref at all (the URL ends after the repo name) which is treated
as equivalent to
HEAD.
Immutable pins that DO satisfy the rule:
- A 40-character hex commit SHA (full).
- A 7-12 character hex short SHA. Git's default short abbreviation is 7; the detector accepts up to 12 for safety.
Tags (v1.0.0, release-2024) and the moving labels listed above
are treated as mutable. Tags can be silently retagged on the remote;
the detector errs toward asking for a SHA pin.
Severity: High. Confidence: High. Evidence signal:
mcp-server-mutable-git-ref, weight 0.8, source Pattern.
Same git URL only fires once per server even when it appears both
inline and behind --from.
Non-compliant config
{
"mcpServers": {
"experimental": {
"command": "npx",
"args": [
"git+https://github.com/vendor/mcp-server-experimental#main"
]
},
"internal-tool": {
"command": "uvx",
"args": [
"--from",
"git+https://github.com/internal/mcp-tool",
"mcp-tool"
]
}
}
}
The main ref on the first entry can be force-pushed. The second
entry has no ref at all, equivalent to HEAD.
Compliant config
{
"mcpServers": {
"experimental": {
"command": "npx",
"args": [
"git+https://github.com/vendor/mcp-server-experimental#a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0"
]
},
"internal-tool": {
"command": "uvx",
"args": [
"--from",
"git+https://github.com/internal/mcp-tool@a1b2c3d",
"mcp-tool"
]
}
}
}
Remediation
- Replace the branch ref with a commit SHA. Use the full 40-char
form (
#a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0) for clarity, or a 7-12 char short SHA when terseness matters. - For an npm-style URL append
#<sha>. Foruvx --from, append@<sha>to the git URL inside the--fromarg. - Update the pin in a controlled review when you genuinely want a newer commit. The risk is silent code substitution at host launch, not the act of bumping the pin.
See also
vulkro mcp-audit- parent CLI command.- MCP-001 - the sibling rule for unpinned registry installs (handles
npx/uvxagainst npm and PyPI). - MCP-006 - catalog hit for a known-compromised release.
- Confidence model - what
High,Medium,Lowmean for MCP findings.