Public AI agent skills instruct agents to install packages that were never published. The names sit unregistered, allocation is first come first served, and the agent does not hesitate. A supply chain attack nobody had to break-in to stage.
A supply chain attack normally requires a compromise. It starts with either breaching a maintainer account, slipping a commit into a dependency, or poisoning a build server. It requires something to be broken into.
In the agentic era, an agent skill is a document an agent executes. Subverting one takes a free account and five minutes: the skill instructs the agent to install packages that were never published. These package names sit unregistered, and allocation on package repositories like PyPI, npm, RubyGems, etc is first come, first served. Whoever claims the name inherits every agent that has been told to install that package, and gets code execution on those machines.
Nothing is broken or breached. Every party in this chain behaved reasonably, and that is precisely the problem.
To demonstrate, we work through one skill in detail because the mechanism is easier to see in action with a single case. Though don’t be mistaken that this is an isolated case. The same defect appears in many skills across unrelated collections, on more than one marketplace, and the conclusions apply to any skill that ships install instructions.
Squatting names a model invents is a known problem, usually called slopsquatting. The attacker guesses which package a model will hallucinate, registers it, and waits. It works, but it is a probability game: the name is generated at inference time and the distribution shifts with the model, the prompt, and the temperature.
Nothing we discuss here is generated at inference time. The name is written down, in a file that is version-controlled, starred, forked, mirrored to marketplaces, and read out to a machine with no opinion about whether it looks plausible. The attacker is not betting on a distribution. The attacker is reading a file that says which name to take.
While most public agent skill scans yield nothing but noise, this one stood out for a remarkably mundane reason.
The skill is called graphql-audit, and it lives in one of the popular bug bounty skill collections on GitHub. It is genuinely good work: a structured GraphQL testing methodology covering introspection, field discovery, injection, authorisation. Near the top there is a setup table, the kind every skill has, telling the agent what to install before it starts.

Four PyPI packages to install. One question to answer: Do all of these packages exist?
Skill Tracer answers the question.

Out of the four, two didn’t exist, and another resolves to a suspicious package. These are the ghost dependencies. The non-existent packages graphw00f and gqlmap can be registered by anyone, thereby taking control of what gets installed as part of the skill execution. On the other hand, the graphql-cop resolves to a package having unrelated lineage and history.
These could become a potential supply chain attack hiding in a popular skill.

This is not an isolated case. The pattern is seen in multiple other skills as well. A skill in a different collection tells the agent to run pip3 install jefferson ubireader. Both are real firmware forensics tools. jefferson resolves. The other does not, because the package has always been published as ubi_reader. One underscore. The name in the skill has never existed.
This is not confined to PyPI packages. Another skill named evolve directs the host agent to run `npx metaharness-darwin`, and guess what, metaharness-darwin npm package did not exist when we scanned. This is the cleanest execution path of the set: npx fetches and runs in one step, so whoever claimed the name would get execution the first time the skill reached that line. We found multiple similar examples across different repositories of different types of packages.

These are not the same mistake, and the difference matters if you want to catch them at scale.
Why is it worse than Typosquatting
A typosquat waits for a human to slip. Most humans do not. This one doesn’t wait. The mistake is already written down, in a file that is version-controlled, starred, forked, mirrored to marketplaces, and read out to a machine that has no opinion about whether a package name looks right. The install line fails deterministically, every time the skill runs. Whether that failure becomes a compromise depends only on whether anyone has claimed the name yet.
We want to be explicit about the minimal effort required here, especially since the security industry is conditioned to look for complex operations, yet there is absolutely none to be found.

There is no vulnerability in this attack. Nothing is exploited. You create a free account, you claim a name nobody owns, you upload an archive. Every one of those actions is the registry working exactly as designed, and it has worked that way for years without anybody considering it a flaw.
What makes it pay is the last panel. Installing a Python package is not a download, it is an execution. A source distribution runs its build logic on the installing machine, as the installing user, before any code is imported. By the time anything could inspect the package, the package has already run.
And it runs somewhere good. A developer workstation with an agentic coding tool on it holds cloud credentials, SSH keys, signing material, source for things that have not shipped, and an API token for the agent platform itself. On this particular skill it also holds engagement scopes and client target lists, because the people who install GraphQL attack tooling are people who are paid to attack things.
The population most exposed to this is people who hunt vulnerabilities for a living, on machines loaded with everything required to do it.
The delivery mechanism is ordinary namesquatting. What is unusual is that the victim population selected itself: the skill's own subject matter did the filtering.

Every property that makes an agent useful makes it worse at this one decision.
It carries no prior about which packages are real. It does not pause at an unfamiliar name. It was handed a document by a source it has been told to trust and asked to perform the setup steps, and performing setup steps is the entire job. A developer who ran pip install gqlmap and watched it fail would go looking for the real tool. An agent installs whatever answers to the name.

Autonomy widens it further. Our scan scored this skill to be highly autonomous, with the note that it presents a checklist and never requires human confirmation between phases, so a host agent can run the whole thing in sequence. Install is phase one. Nobody is watching phase one. Nobody has ever watched phase one.
Publishing a list of live unclaimed names that public skills instruct agents to install would be publishing a target list. So before this article was written, our labs team registered graphw00f and gqlmap (and other dangling packages we discovered like metaharness-darwin), to take them out of circulation.
Every name we registered has received downloads since we took it. None of these is a real tool, none is referenced by anything other than the skills that named it, and none of them should be resolving to anything at all. We are not claiming those downloads are all via agents. Newly published packages attract automated scanners, and we have not separated that traffic. The point here is, each of these names is being resolved by something on a recurring basis, and until we registered them the answer to that resolution was whatever anyone chose to put there.
None of these packages registered by our labs contain working code. Each carries a description stating that it is a hold on an unclaimed name referenced by a public agent skill, that it is not the real tool, and that it collects nothing. Each lists a contact address. All are MIT licensed, and all will be transferred to the legitimate tool authors on request, without conditions, under PyPI's name transfer policy Disclosure. We notified the tool authors of the package names we have reserved, offering unconditional transfer of the package names on request. We hold no functional code and collect no data. No trademark holder is affiliated with or endorses these holds.
The collection this came from is not obscure. Roughly five thousand stars, more than seven hundred forks, republished across multiple third-party skill marketplaces, installed with one git clone into the agent’s skills directory.

The fork row is the one to sit with. A maintainer who reads this and fixes their install lines tomorrow has fixed their repository. They have not fixed the several hundred copies, and they have no mechanism to.
Checking that a name exists is one API call. Checking that the package at that name is the project the skill meant is harder, and that is the half that fails silently. Across a whole collection, on every update, it is a CI job: a release gate if you publish skills, an ingestion gate if you host them, a recurring check if you install them. We built SkillTracer for this, and it produced the findings discussed here.
The skill author wrote install instructions. The tool authors published on GitHub instead of PyPI, which is allowed and common. PyPI allocates names first come first served, which is how it has always worked and mostly works fine. The agent followed the setup steps in a document it was handed, which is the entire function of an agent. Every participant behaved reasonably, and the sum of all that reasonable behaviour is a remote code execution path onto the workstation of every security researcher who runs this skill, available to anyone with a free account and no particular skill.
We, as a community, have spent years hardening the artifacts in the supply chain. Signing, SBOMs, dependency scanning, version pinning, provenance attestation. All of it assumes the dependency exists. Every one of those controls operates downstream of the failure described here, because you cannot sign, scan, pin or attest a package that nobody has written yet. The vulnerability is in the sentence, not in the software.
Agent skills are executable documents. We ship them with the informality of a README and the blast radius of a build script.
And we hand them to something that reads instructions more literally, and far less suspiciously, than any human ever has.
Go and check your install lines. It is one API call per name, and right now that call is the entire control.
Every status in this article was checked at the time of writing.

Apart from the above, there are more package names that we discovered, registered, and now hold, to disallow anyone with a malicious intent to perform a supply chain attack via those. As mentioned earlier, we have informed the upstream tool authors where one exists, and we will unconditionally transfer the ownership on request.
Checkout the SkillTracer here https://labs.metano.ai/scanner