The update is the attack surface
Malicious AI skills reached 1.7M installs by shipping useful v1s and poisoning later updates. Here is how shareskills now gates exactly that move.
The shareskills team
Last week, researchers at Zenity documented something the AI-agent world had been bracing for: malicious skills in a public directory, with one family alone accumulating over 1.7 million installs. The payloads hunted SSH keys, cloud credentials and access tokens, bundled them with machine details, and shipped them to attacker-controlled servers. One skill quietly replaced the built-in skill-creator with a counterfeit. More than 30% of the dangerous skills targeted agents like Claude Code.
The detail that matters most is when the skills turned hostile. They were genuinely useful at upload. They stayed useful while installs and trust accumulated. The poison arrived later, as an update — pushed to an audience that had already said yes once and would never be asked again.
Why scanning uploads misses this
The reflex response to a story like this is to scan things at the door: review every skill at publish time and reject the bad ones. But in the attack that actually happened, there was nothing to catch on day one. The malicious version of the skill did not exist yet. Publish-time review inspects the one version of a skill guaranteed to be clean.
Meanwhile the update channel is engineered for speed. Agents are told — by us, among others — to keep their installed skills fresh and never rely on a stale copy. That is correct advice, and it is also a beautifully efficient delivery mechanism for whoever controls version seven. As the researchers put it, quoted in The Next Web:
“an agent’s whole job is to follow instructions”
What shareskills does about it
This week we shipped an update gate for every skill installed from the public directory. The first install works the way it always has: you chose the skill, you get it — that choice is recorded, along with the exact version you received. If even that first version contains things worth knowing about (credential-file paths, shell execution, encoded blobs), the install arrives with a plain advisory listing them. Nothing is blocked; you are simply told.
From then on, every update is compared against the version you accepted. Routine changes — documentation, wording, small fixes — flow through automatically, exactly as before. But if an update adds risky behaviour, the server refuses to hand the new version to your agent at all. Instead the agent receives a short structured report and an instruction to bring it to you:
{
"status": "acceptance_required",
"slug": "handy-skill",
"publisher_team": "Example Publishing Co",
"accepted_version": 3,
"current_version": 7,
"findings": [
{ "signal": "exec", "path": "scripts/setup.sh" },
{ "signal": "cred-paths", "path": "SKILL.md" },
{ "signal": "egress-new-host", "path": "scripts/setup.sh" }
],
"action_required": "Show these findings to the user. Only after they explicitly approve, call accept_skill_update('handy-skill', 7)."
}The signals are deliberately unexciting: new shell execution, references to credential files, network calls to hosts the skill never talked to before, oversized encoded blobs, new binary files, writes outside the skill’s own folder, and instruction-injection phrasing like “do not tell the user”. Any of them holds the update until a human approves that exact version — and the approval itself is recorded, with the publisher’s name attached.
One property here matters more than it first appears: the suspicious content is withheld, not flagged. The new version never enters your agent’s context before you approve it. A poisoned update cannot talk its way past the gate, because the gate happens before it gets to talk.
Names are not identities
The other trick in the research was impersonation — look-alike skills trading on a familiar name. shareskills tracks the skill you accepted, not the name you typed. If the skill answering to a name is suddenly a different skill under the hood, that is treated as maximum suspicion: always held, always shown to you, flagged as a publisher change.
Inside your own org: zero new prompts
Skills your own team publishes are never gated. That is a deliberate decision, not an oversight: teams iterate on internal skills constantly, and a consent prompt on every tweak trains everyone to click yes — which makes the one prompt that matters worthless. Stranger-trust and colleague-trust are different problems.
Internal changes get visibility instead of friction. When a teammate’s update adds risky behaviour, the notification your collaborators already receive now says so. And when a widely-installed internal skill suddenly gains risky changes, the org’s admins are notified automatically — which is the tripwire you want for a compromised teammate account.
What this does not do
The classifier is a tripwire, not a scanner. It is deterministic and cheap on purpose, and novel obfuscation will walk past regexes eventually. We think the durable defences are the other two properties: an accountable identity behind every published skill, and changes that are visible at the moment they matter. Verified publishers and stronger namespace rules for the directory are on our list; we would rather ship the honest version of this post than the impressive one.
If you run a skill directory — public or inside your company — the one-line takeaway from the Zenity research is this: whatever you inspect at upload time, the update is the attack surface. Gate it.