Plugin version resolution walks out of a non-git marketplace dir and records the user's own repo HEAD
Summary
When a marketplace directory under ~/.claude/plugins/marketplaces/ is not a git
repository, plugin version resolution appears to run a git command with that directory as
the working directory. Git then walks up the filesystem, and if ~/.claude happens to
live inside the user's own git repository, it resolves to that repository instead. The
user's own HEAD is then written into installed_plugins.json as the installed plugin
version.
On my machine 17 of 30 plugin entries carry a commit SHA from my personal repository.
Environment
- Claude Code 2.1.220, macOS
~/.claudeis inside a git repo rooted at$HOME(I version-control my config)- Marketplace:
claude-plugins-official
Evidence
claude-plugins-official is materialized as a tarball drop, not a clone. It has no .git,
though known_marketplaces.json declares {"source": "github", "repo": "anthropics/claude-plugins-official"}:
$ ls -a ~/.claude/plugins/marketplaces/claude-plugins-official
.claude-plugin .gcs-sha .gitignore external_plugins LICENSE plugins README.md
So git walks up out of it:
$ cd ~/.claude/plugins/marketplaces/claude-plugins-official && git rev-parse --show-toplevel
/Users/<me> # my repo, not the marketplace
$ cd ~/.claude/plugins/marketplaces/claude-code-warp && git rev-parse --show-toplevel
~/.claude/plugins/marketplaces/claude-code-warp # a real clone, unaffected
installed_plugins.json then records my HEAD:
"frontend-design@claude-plugins-official": [{
"version": "2904b9bee772",
"gitCommitSha": "2904b9bee772...",
"installPath": ".../frontend-design/2904b9bee772",
"lastUpdated": "2026-08-02T07:37:36.000Z"
}]
2904b9bee772 is a commit in my repository, message docs(fable-parity): ....
The part that makes it unambiguous
I measured this on two consecutive days without touching plugins.
- 2026-08-01: my HEAD was
81c1517c2f9f. Nine plugins recordedversion: "81c1517c2f9f". - 2026-08-02: I committed unrelated work; HEAD became
2904b9bee772. After a marketplace
refresh, the same nine plugins recorded version: "2904b9bee772".
No plugin was installed, updated, or removed between those readings. The recorded version
tracks my repository's HEAD.
Scope
- 9 of 30 entries have
versionequal to a 12-char prefix of one of my commits. - 17 of 30 have a
gitCommitShathat resolves as an object in my repository. - The wider set includes entries whose
versionlooks like a clean semver, so the field
alone does not reveal the problem. security-guidance reads "version": "2.0.6" while
carrying gitCommitSha: 6a4debc2..., a merge commit in my repo from 2026-06-12.
- Affected SHAs date back to 2026-04-20, so this is not new.
Why it is easy to miss
installed_plugins.json is covered by a .gitignore rule, so the churn never appears ingit status, and there is no history to recover a correct value from. The SHA is also used
as the installPath directory name, so cache directories are named after unrelated commits.
Impact
Version pinning is unreliable for any user whose ~/.claude sits inside a git repo, which
is a common way to version-control Claude Code configuration. Reproducing an environment,
diagnosing a plugin regression, or answering "which version am I running" all read a field
that is really a snapshot of the user's own unrelated work.
Suggested fix
Constrain version resolution to the marketplace directory rather than letting git walk up.
Any of these would do it:
- Resolve, then verify: run
git -C <marketplace> rev-parse --show-topleveland require
the result to equal <marketplace> before using the SHA.
- Set
GIT_CEILING_DIRECTORIESto the marketplace's parent, or pass
--git-dir=<marketplace>/.git, so the walk cannot escape.
- For a tarball-materialized marketplace, prefer the
.gcs-shaalready written alongside
the content, and fall back to the plugin manifest's own version.
A guard for case 1 seems worthwhile regardless, since "the SHA I just read belongs to a
repository I do not control" is checkable and currently unchecked.
Happy to supply more detail or test a fix.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗