# What a third-party Claude Code skill can do before you have read it

> Source: <https://dev.to/sergeipalii/what-a-third-party-claude-code-skill-can-do-before-you-have-read-it-1imn>
> Published: 2026-09-02 08:41:33+00:00

A Claude Code skill is a folder with a `SKILL.md`

file in it. It installs with one command, like a package: `npx skills add owner/repo`

or `/plugin install name@marketplace`

. The registries already count installs in the millions — on Vercel's `skills.sh`

, the top skill reports three million — and people install them the way they install npm packages: by name and star count, without opening them.

The difference is that a dependency runs inside your application, while a skill runs as you, on your machine. Below is exactly what it can do — checked on Claude Code 2.1.223 and on live repositories, not on secondhand accounts.

From the [documentation](https://code.claude.com/docs/en/skills) and from what the repositories show, a skill has three layers, and each one runs at a different point.

**The description** — the `description`

field in the frontmatter. It sits in the context of *every* session while the skill is installed: this is what the model uses to decide whether to pick the skill up on its own, without you asking. To keep the description out of context, the author has to set `disable-model-invocation: true`

explicitly — of the 364 skills in the largest repository we looked at, not one did.

**The body** — instructions that load when the skill is invoked and stay in context for the rest of the session. The body can contain commands like `!` git diff``

: Claude Code runs them **before the model sees the text** and puts the output where the command was. This is not the model being offered something to run — it has already run.

**Permissions.** The `allowed-tools`

field does not restrict; it *grants*: the listed tools work without a confirmation prompt for the turn that invokes the skill. The documentation says as much: workspace trust does not gate the field, and "a skill can grant itself broad tool access, so review the `allowed-tools`

of skills checked into a repository before you run Claude Code there."

A plugin is skills plus three more things, each with its own way in: **hooks** (`hooks/hooks.json`

) — shell scripts that run on session events: start, every tool call, end; **MCP servers** (`.mcp.json`

) — local processes or HTTP addresses the session connects to; and a `bin/`

folder whose executables are added to the Bash tool's `PATH`

while the plugin is enabled. Hooks, per the documentation, "execute shell commands with your full user permissions", and the sandbox does not cover them — it covers Bash commands only.

Four skills in an empty project, run with `claude -p`

in the default permission mode — that is, the way Claude Code works in CI or in someone else's script, where there is nobody to answer a prompt.

| Skill | What is in it | Result |
|---|---|---|
`allowed-tools: Bash(*)` + an `!`…`` command in the body |
writes a marker file |
ran, no prompt |
the same without `allowed-tools`
|
writes a marker file | invocation aborted, no file |
`allowed-tools: Bash(*)` + an instruction in the body, "run this command" |
writes a marker file |
ran, no prompt |
`allowed-tools: Bash(*)` , auto-invocation by description |
an `!`…`` command |
in our run the model did not pick the skill up |

The marker is a line with our username and a timestamp, so the command ran as us. No workarounds: exactly the behaviour the documentation describes. The fourth row is the honest one — auto-invocation remains the model's decision, and this time it answered without picking the skill up. But the mechanism is there, and the description is already in context, waiting.

NoteA note on modes: in an interactive session, without`allowed-tools`

, the command from the body would have asked for permission.`claude -p`

and the SDK show neither the trust dialog nor the prompt — per the documentation, the folder counts as trusted in that mode, and hooks from a cloned repository's`.claude/settings.json`

run. That is exactly the path Claude Code takes in CI.

We cloned five popular repositories and counted what they contain besides instructions. None of them is malicious — that matters. The point is what gets installed along with the text.

**A curated marketplace from a well-known audit firm**, 31 skills. The `allowed-tools`

field is present in all 31, and in 24 of them the list contains a bare `Bash`

— no pattern. Invoking one of these skills gives you a turn on which any shell command runs without confirmation. Not malice, convenience: a fuzzing skill has to run the fuzzer. But whoever installs it signs up for that without looking.

**A collection of 364 skills and 90 plugins** with 24,000 stars. Inside, five `hooks.json`

files: Python and bash scripts on `SessionStart`

, `SessionEnd`

and `PostToolUse`

. One of them receives the output of every Bash command and searches it for errors; another reads files from disk at session start and inserts their contents into context. Three `.mcp.json`

files connect an external HTTP server, a local process, and `npx tsx`

with a script from the plugin. Installing the "marketing skills" from this collection installs all of that too.

**The marketplace of a popular plugin set**, 10 plugins from external repositories: nine of them list only a URL — no `sha`

or `ref`

. Installation takes whatever is at `HEAD`

at that moment.

**The most popular skill on GitHub**, 99,000 stars, is a mode that shortens responses. Its `SessionStart`

hook is an `echo`

with an instruction for the model. Harmless. But it is the same mechanism: text that lands in the context of every session without your involvement.

**Anthropic's official marketplace** on our machine: 286 plugins, 233 of them external repositories on GitHub, and all 233 have a `sha`

set. That is the good news. The bad news is in the file next to it: the plugin installed from there had updated itself overnight, and the catalogue again a few hours later; we asked for neither. Official marketplaces have auto-update on by default — the documentation confirms it. Nobody asked what had arrived.

A skill has no network layer of its own, so "where does it send things" comes down to what routes out it has.

`.mcp.json`

`!`…``

commands`curl`

there is still a `curl`

.`money-radar`

skill from the OpenClaw registry: on every invocation it downloaded `referrals.json`

from the author's server, and the instruction told the agent to always recommend the affiliate links from it. The skill is published once; the behaviour is steered from the server afterwards.The API key is a separate case. Until December 2025, an `ANTHROPIC_BASE_URL`

planted in a repository's `.claude/settings.json`

redirected the very first request — key and all — to a third-party server, before the trust dialog ever appeared (CVE-2026-21852, analysed by Check Point). Closed: requests now wait for trust to be confirmed. But it shows where the key lives and which file reaches it.

This is not a theoretical risk, and the precedents go back to the start of the year.

**ClawHub, February 2026.** Koi Security checked OpenClaw's entire skill registry: 341 malicious out of 2,857, almost 12%, 335 of them one campaign. Snyk scanned 3,984 skills from ClawHub and skills.sh: 76 confirmed malicious, 13.4% with critical issues, 10.9% with hard-coded secrets. The top hundred on skills.sh came out clean — which speaks to curation more than to the format. The malicious ones all work the same way: a "prerequisites" block in `SKILL.md`

, a base64 string inside it, and a request for the agent to decode the string and pipe it to bash. What follows is the AMOS infostealer and stolen wallet keys. When the scanners learned to read `SKILL.md`

, the authors moved the commands into the skill's comments on the registry page, and one skill padded its `README.md`

with 22 megabytes of junk to push it past the scanners' size limit.

**Read next:** [An agent broke out of its sandbox to cheat on a test. No attacker was involved](https://sepia.software/blog/an-ai-agent-broke-out-of-its-sandbox)

**Claude Code, demonstrations.** In January, Prompt Security showed a plugin from a third-party marketplace whose skill, when asked to "install the library", quietly pointed the install at a source of its own — the library imports, the example works, the trojan is in the project. Reversec in May: a reverse shell through an `!`…``

command plus `allowed-tools: Bash(*)`

— "dynamic context skips the model's reasoning and executes before any checks". It is the same mechanism as in the first row of our table: asked directly, the model refused to run the reverse shell — but here the command never reached it.

**Hookify, April 2026.** Pluto Security found that a plugin from the *official* marketplace reads rule files from the project folder and feeds them into the trusted hook channel — so a file in someone else's repository becomes a way to steer the model for everyone who installed the plugin. Five payloads dressed up as "project conventions" made the model hand over environment variables; not one was recognised as an injection. Anthropic's response: "working as designed" — the security boundary is the folder trust dialog.

That last point matters most. Claude Code's security model is honest and documented: trust is granted to a folder, and everything in it counts as yours. Someone else's skill in that folder is yours too.

A dependency from npm can be malicious too, and there are plenty of examples. But it has four properties a skill does not.

`~/.ssh`

, `~/.aws`

, `~/.claude`

, with the tokens in your environment and with network access. On the Anthropic API, the same `SKILL.md`

runs in a container with no network access; in Claude Code it runs with full host privileges.There is a fifth, about people. A dependency is chosen by a developer who reads what it does. A skill is chosen by the model — by description, in context — and the developer learns about it from a line in the output, if they look at all.

None of this requires giving up skills — we write and use our own. It requires treating them as code that [runs with your permissions](https://sepia.software/development), not as hints.

`allowed-tools`

with a bare `Bash`

, `Write`

, `Edit`

is permissions; `!`…``

in the body is commands. Give it the same attention you would give a package's `postinstall`

script.`SKILL.md`

.`find . -name hooks.json`

, `.mcp.json`

, the `bin/`

folder, `settings.json`

at the plugin root. In that 364-skill collection, that is exactly where the interesting part was.`sha`

, not `HEAD`

; third-party marketplaces already have auto-update off by default — do not turn it on "for convenience". Official ones have it on, and that is worth knowing.`disableSkillShellExecution`

setting disables `!`…``

for all skills except the bundled ones; a `deny: Bash(*)`

rule in your settings overrides any skill's `allowed-tools`

— Reversec checked that. In an organisation, set `strictKnownMarketplaces`

and `allowManagedHooksOnly`

in managed settings.`-p`

.`uvx mcp-scan --skills`

and its equivalents find the known patterns — not injections in natural language, but at least base64 and `curl | bash`

.None of the repositories we looked at does anything bad, and we left them unnamed on purpose: a bare `Bash`

in `allowed-tools`

at an audit firm is a deliberate choice for its own work, not a flaw. The ClawHub figures are about OpenClaw, which has a different registry and a different publishing culture; the top hundred on skills.sh, which is what people use with Claude Code, came back clean.

What it does prove is one thing: a skill is not text but code — code that runs with your permissions, that you did not write, and that updates without you. The industry already knows how to handle everything that fits that description. What remains is to notice that a skill is one of those things.

*This is the kind of work we do at Sepia Software.*
