Malicious Skills and Plugins

Six published incidents on ClawHub and in Claude Code · the 15 checks measured 20 September 2026 on skills.sh and Anthropic's two plugin marketplaces

What this is. In the first week of February 2026 three research teams separately published malicious skills on ClawHub, the OpenClaw agent's registry: Koi Security counted 341 of 2,857 (as quoted by The Hacker News — Koi's own post can no longer be read), Snyk traced two skills named after the registry itself to a password archive and a base64 line piped into bash, and Snyk's ToxicSkills audit of 3,984 skills from ClawHub and skills.sh confirmed 76 malicious payloads by hand. In May and June Reversec showed the same idea inside Claude Code — a skill whose dynamic-context line runs before the model reasons — and Datadog found a live skill doing it. This page states each incident with its date and primary source, the ecosystem the 15-check roster (S1–S15) reads, what the roster found on the three lists people actually install from, and the one thing the record makes plain first: no malicious plugin has been publicly reported in either Anthropic marketplace, and no skills.sh skill has been named malicious by a primary source. The campaigns lived on ClawHub, which is parsed and routed but not assessed on this tier. Neither number below is a guarantee of anything — see “What this doesn't mean”.

The incidents

Two research notes frame the rest. The Cloud Security Alliance's 6 May 2026 note on “Agent Context Poisoning”: “The attack surface is not a code path — it is a document that agents are designed to trust and follow.” (It repeats Snyk's figures and attributes Koi's 341 to Snyk, which is wrong; this page does not.) And its 10 June note, “AI Agent Skill Scanners: Bypassed Across the Board”: ClawHub's VirusTotal Code Insight bypassed by whitespace inflation of roughly 100,000 newlines before the payload, Cisco's skill scanner by a precompiled .pyc, skills.sh's audits by embedding the payload in a DOCX, LLM-based layers by prompt injection; “No single scanner caught all four malicious skills”; three of the four bypasses “required less than one hour to develop”; “Don't outsource trust to a scanner”. That last line applies to this roster too, and the measurement below is read with it in mind.

Nothing on the marketplaces, nothing named on skills.sh

Searched on 20 September 2026 for every combination of “malicious skill”, “malicious plugin”, ClawHub, skills.sh, Claude Code, SKILL.md and marketplace: everything that surfaced traces to the incidents above or to secondaries of them. No malicious plugin has been publicly reported in anthropics/claude-plugins-official or anthropics/claude-plugins-community, and no skills.sh-hosted skill has been named as malicious by a primary write-up — skills.sh appears in the record as one of ToxicSkills' two sources and as a scanner-bypass target, nothing more. So this page names ClawHub campaigns and Claude Code attack shapes, and never a marketplace campaign that did not happen.

The ecosystem the checks read

The Agent Skills specification (agentskills.io; “originally developed by Anthropic, released as an open standard”): a skill is a directory with a required SKILL.md and optional scripts/, references/ and assets/; frontmatter name (required, at most 64 characters, lowercase letters, digits and hyphens, matching the parent directory) and description (required, at most 1,024); compatibility (at most 500, “environment requirements (intended product, system packages, network access, etc.)”); allowed-tools (“Space-separated string of pre-approved tools the skill may use. (Experimental)”); “Keep your main SKILL.md under 500 lines.” Claude Code adds its own fields, among them the dynamic-context !`command`, which runs “before the skill content is sent to Claude”. skills.sh installs with npx skills add owner/repo from GitHub, discovering SKILL.md at the root, under skills/ and under some fifty agent directories; its README carries no statement on signing or verification; its leaderboard header reads “All Time (1,480,226)” with no unit, and per-skill install counts have no API; its Audits page combines Gen, Socket and Snyk, and 23 of the 50 skills shown were Pending. ClawHub keys skills as @owner/slug; its API answers a skill with its SKILL.md text and a moderation object, and carries no source repository, no file list and no checksum. The Claude Code marketplaces: the official one is “curated by Anthropic, and inclusion is at Anthropic's discretion”, with the README's own line that “Anthropic does not control what MCP servers, files, or other software are included in plugins and cannot verify that they will work as intended or that they won't change”; the community one “hosts third-party plugins that have passed Anthropic's automated validation and safety screening”, each “pinned to a specific commit SHA”. A plugin's source takes seven forms, including an archive and a command run on the user's machine; the docs' own sentence is that “Plugins and marketplaces are highly trusted components that can execute arbitrary code on your machine with your user privileges.” Two entry points, stated wherever the hook is named: /plugin install name@marketplace is a slash command inside the session, which no PreToolUse hook sees; claude plugin install name@marketplace is a shell line.

What the roster matches

Fifteen checks, each with its own page, on the two things a skill is: a repository someone published, and a document an agent follows. S1 runs the 22 repository checks on the source and lets their verdict ride along; S2, S3 and S4 read the listing's age, its owner's, traction that outruns them, and a name one edit from a known one — the clawhub beside ClawHub. S5, S6 and S7 read what the skill declares — its frontmatter, its allowed-tools, an agent's permissionMode. S8 reads for invisible codepoints, and S9 matches nine named shapes in the text: the base64 line piped into a shell, the password archive beside a URL, curl piped into sh, a read of ~/.aws/credentials, a send to a paste host, a dynamic-context command that fetches or opens a relay, a permission-bypass flag, an “ignore previous instructions” phrase, any of those in an HTML comment — each with a 60-character negation window, so a skill that warns against a shape does not fire. S9 matches these shapes; it does not detect prompt injection, and no page of this site says it does. S10 reads the scripts beside the skill as code and lists the binaries it cannot read; S11 notes size. For a plugin, S12 reads how the marketplace pins it, S13 and S14 apply the C20 shell-fetch rule to its hooks, monitors and MCP servers, and S15 reads for a base URL pointed at a stranger's host. The tier reads the listing record, the tree once, and at most twelve files of 64 KB each; the deep scan reads the whole package.

Measured on skills.sh and the two Anthropic marketplaces

Run on 20 September 2026 through the product's own engine, the same code as /v1/skill/score, under the 6.5-second deadline, after the calibration the first run of the same day forced. Three lists, and the named incidents:

SetKeysPASSREVIEWBLOCKPartialMedian · p90 · max
skills.sh — the leaderboard's top 100 as 28 repositories and 161 listings189153360231.5 s · 2.1 s · 3.5 s
Official marketplace — all 310 plugins3102822801102.2 s · 3.0 s · 4.3 s
Community marketplace — the first 1001009460232.6 s · 3.3 s · 4.9 s
The named incidents — 19 keys, 12 of them assessable1983132.8 s · 4.0 s · 4.4 s

Of the 19 incident keys, 3 answer “gone” — repositories no longer on GitHub, the two ClawHavoc payload hosts among them — and 4 are ClawHub keys, not assessed on this tier; every one of the seven is a warning, never a pass. The one BLOCK is Snyk's own fixture repository, snyk-labs/toxicskills-goof: critical hidden Unicode in its “testing-guidelines” skill (171 tag codepoints — the ASCII smuggling of the ToxicSkills post), the fake vercel skill's curl --data "$(uname -a)" to a paste host under two directories, a curl … | bash, a !`curl … | bash` dynamic-context line, and a cat .env beside the send — four of the roster's shapes at once, on the repository written to exercise them. Datadog's clawsights/clawsights is REVIEW 40 on two reads of ~/.claude/… and two sends, exactly the shape the write-up describes; ToxicSkills' aztr0nutzs/NET_NiNjA.v1.2 is REVIEW 62 on its three archives, with 116 of its 128 files unread on this tier. The repo-jacked community entries, present today and SHA-pinned, pass.

What a REVIEW meant on the three lists. On skills.sh, 28 of the 36 are five repositories — 101-skills/superpowers, designed-by-ai/skills, flowkit-labs/skills, genmedia-labs/skills, prime-skills/runcomfy-agent-skills — under owners between 16 and 74 days old, whose own C1/C2 verdict is BLOCK and which carry 31 listings between them, each riding the repository's verdict on S1 and S2: five signals, not 28; two are an archive beside a SKILL.md on anthropics/skills and vercel-labs/agent-skills (S10, graded HIGH by the letter of the rule and marked for review); six are one owner's directories named *-skill against their frontmatter names (S5). On the official marketplace, fifteen of the 28 are what the shape says or as designed — Carta's, Semgrep's and Zscaler's compiled hooks and zips, empty names and a missing description, jfrog writing a token into ~/.netrc and saying so, Vercel's own gateway redirect beside a --dangerously-skip-permissions line — five are gradings decided and listed so they can be revisited, and eight are misreads the record names one by one with the rule that closes each: a sentence describing what a tool blocks, a description of ~/.aws/credentials as an INI file, a vendor's installer on its short domain or behind a variable, a plugin's own repository on GitHub's raw host, a POST to a placeholder host, defence text about third-party data, a -skill suffix on a directory. On the community marketplace, four of the six are real or graded and two are one misread. None of the misreads is a BLOCK; the worst is a REVIEW on a line the skill's author would recognise as their own. The REVIEW rates — 36 of 189, 28 of 310, 6 of 100 — are printed with their drivers because a rate without them is a number to hide behind.

The first run, and what it forced. The same day's first measurement said 49 PASS / 256 REVIEW / 5 BLOCK on the official marketplace and 0 / 99 / 0 on the community one, and every BLOCK was the roster's. Two were product defects: every plugin key answered “not assessable” in production because the marketplace catalogue was read through the 64 KB per-file cap (the official catalogue is 185,864 bytes, the community one 1,565,989), and a YAML date under a skill's metadata raised an error. The rest were gradings: the lookalike check comparing a catalogue entry to itself (250 official and 98 community false fires, to none); the credential-redirect rule firing on the name of a variable rather than an assignment (five of the six BLOCKs); a listing of dangerous shapes in a table read as an instruction; a defence against “ignore previous instructions” read as the phrase; a vendor's own installer read as a stranger's; a script's docstring read as its code; a fresh repository from an established owner graded as though the owner were new too. Each rule has its evidence row pinned in the roster's tests and its letter on the check page it changed. The numbers above are from the run after them.

The gate. The roster shipped against a stated condition: zero false BLOCKs on the three lists, the false-REVIEW rate printed with its drivers, every reconstructed fixture at REVIEW or worse and the four campaign shapes — the clawdhub macOS and Windows files, the ToxicSkills AWS and helper-zip files — at BLOCK, timing under the deadline from a far client, and every partial scan counted. Met on 20 September 2026: 0 BLOCK on 189, 310 and 100 keys; medians 1.5 s on a skill key and 2.2–2.6 s on a plugin key, p90 no worse than 3.3 s, no row at the deadline; 159 partial scans, every one the twelve-file cap's note or a source repository not visible, none silent. Eleven remaining misreads are listed in the measurement record with a proposed rule each; none is a BLOCK.

Why the PASS rate is not Mondoo's

Mondoo's AI Skills Check product page, read on 20 September 2026, shows a live counter that Mondoo does not date: 58,983 skills scanned, 47,054 threats, 11,929 “clean” — 20% — with 3,195 critical, 17,565 high, 74,836 medium and 57,680 low findings; five registries (ClawHub, skills.sh, GitHub, the Claude marketplace, SkillsMP); a six-layer pipeline with 59 regex rules, 13 YARA rules and 28 threat subcategories. Its launch release of 21 April 2026 named no scan total and cited “1,184 malicious skills identified on ClawHub in 2026” — Antiy's figure, unattributed there. Those are Mondoo's numbers, stated as Mondoo's, and this roster's 153, 282 and 94 PASS on 189, 310 and 100 keys is not the same measurement, for four reasons.

  1. Different sets. Mondoo's counter runs over the whole of five registries, including the ClawHub long tail where every campaign above lived; these sets are the hundred most-installed skills.sh skills and Anthropic's two reviewed catalogues. A scanner of the whole registry should find more.
  2. Different arithmetic. Mondoo's “clean” is zero findings of any severity, and its own counter carries 74,836 medium and 57,680 low findings, so a skill with one low finding is not “clean” there. RepoGates' verdict is the maximum over its checks, and a note never moves it: a declared allowed-tools: Bash(*), a compatibility line asking for the network, a bin/ directory or an MCP server on an established listing is a note, because that is what the skill declares it does — the same principle that graded the VS Code and Docker Desktop rosters before it. A PASS here is “nothing matched on what was read”, not “clean”.
  3. Different method. Mondoo runs an ML prompt-injection classifier and LLM analysis. This tier matches named regex and structure classes with a 60-character negation window, prints the calibration of every class by name on the S9 page, reads at most twelve files and 64 KB per file, and makes no claim about prompt injection; the deep scan reads everything, and the customer-key AI review on an over-cap scan is the customer's own model, not RepoGates'.
  4. Every scanner is bypassable, this one included. The Cloud Security Alliance's 10 June note defeated four vendors' scanners with whitespace, bytecode, a document and a rephrasing, three of the four in under an hour. A PASS from RepoGates is subject to the same limit — which is why the verdict is a gate on the download and the install line, backed by a blocklist that does not depend on matching, and never a promise.

What actually blocks these, in the product

Five entries in RepoGates' campaign blocklist (platform: skill, confidence: confirmed, source Snyk's ToxicSkills post of 5 February 2026, expiring 20 September 2027) — the operators the post names, zaycv, Aslaep123, pepe276 and moonshine-100rze, by owner across every source a skill key can carry, and the payload repository aztr0nutzs/NET_NiNjA.v1.2 by key — run ahead of the roster and ahead of an account's own allowlist. An owner entry is the unit that matters here because it was the campaign's unit: accounts days old, publishing dozens of skills each, and re-registering when removed (Snyk on google-qx4: “clones often pop up within hours”). A skill whose source repository is listed is critical on S1 whatever the text says. The roster table above is what the checks alone found; the blocklist is the product's behaviour on these names. The ecosystem feed carries the campaign family as its sixth lane, with this page as its intelligence link.

What is not assessed

ClawHub. The registry every campaign above lived on. A ClawHub key (@owner/slug) is parsed and routed but not assessed on this tier: no listing, SKILL.md or script is read there yet, every text check is a listed skip, and the verdict is “not assessed” — which the preflight and the MCP tool answer as ask, and which is never a pass. The ClawHub fetch is on the roadmap with the gate it must pass first: the same measurement on ClawHub's top 100. A skill with no provenance — pasted from a chat, a gist, a zip — has no repository record to read and no listing, and the roster has nothing to say about it. Runtime behaviour. Nothing here runs a skill, opens an archive, follows a package name into a registry, or watches what an agent does with a grant it was given; the metadata tier reads text, the deep scan reads a package, and the agent check-up on the roadmap is where an installation's own skills, hooks and servers will be read. 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: npx skills add owner/repo and claude plugin install name@marketplace are shell lines it judges; /plugin install is a slash command the hook never sees; a skill copied by hand into ~/.claude/skills is never seen at all.

What this doesn't mean

A skill or plugin that scores PASS today was checked today, on its source repository, its listing, what it declares and the text this tier read — at most twelve files of 64 KB — against nine named shapes and the C19–C21 rules. It is never a claim that the text is benign, never a claim about a script or an archive the tier listed and did not open, never a claim about what the skill does once an agent follows it, and never a claim about a ClawHub skill, which is not assessed here. Every marketplace and registry named above passed the campaigns' skills through its own review; the roster reads those reviews as necessary, never as sufficient, and asks the same of itself.