{"slug": "what-a-third-party-claude-code-skill-can-do-before-you-have-read-it", "title": "What a third-party Claude Code skill can do before you have read it", "summary": "A developer demonstrated that third-party Claude Code skills can execute arbitrary shell commands without user confirmation before the model reads their instructions. In tests with Claude Code 2.1.223, skills with `allowed-tools: Bash(*)` and `!`...`` commands ran automatically in default permission mode, writing files as the user. The developer warns that skills can grant themselves broad tool access and that plugins can run hooks with full user permissions, urging review before use.", "body_md": "A Claude Code skill is a folder with a `SKILL.md`\n\nfile in it. It installs with one command, like a package: `npx skills add owner/repo`\n\nor `/plugin install name@marketplace`\n\n. The registries already count installs in the millions — on Vercel's `skills.sh`\n\n, the top skill reports three million — and people install them the way they install npm packages: by name and star count, without opening them.\n\nThe 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.\n\nFrom 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.\n\n**The description** — the `description`\n\nfield 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`\n\nexplicitly — of the 364 skills in the largest repository we looked at, not one did.\n\n**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``\n\n: 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.\n\n**Permissions.** The `allowed-tools`\n\nfield 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`\n\nof skills checked into a repository before you run Claude Code there.\"\n\nA plugin is skills plus three more things, each with its own way in: **hooks** (`hooks/hooks.json`\n\n) — shell scripts that run on session events: start, every tool call, end; **MCP servers** (`.mcp.json`\n\n) — local processes or HTTP addresses the session connects to; and a `bin/`\n\nfolder whose executables are added to the Bash tool's `PATH`\n\nwhile 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.\n\nFour skills in an empty project, run with `claude -p`\n\nin 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.\n\n| Skill | What is in it | Result |\n|---|---|---|\n`allowed-tools: Bash(*)` + an `!`…`` command in the body |\nwrites a marker file |\nran, no prompt |\nthe same without `allowed-tools`\n|\nwrites a marker file | invocation aborted, no file |\n`allowed-tools: Bash(*)` + an instruction in the body, \"run this command\" |\nwrites a marker file |\nran, no prompt |\n`allowed-tools: Bash(*)` , auto-invocation by description |\nan `!`…`` command |\nin our run the model did not pick the skill up |\n\nThe 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.\n\nNoteA note on modes: in an interactive session, without`allowed-tools`\n\n, the command from the body would have asked for permission.`claude -p`\n\nand 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`\n\nrun. That is exactly the path Claude Code takes in CI.\n\nWe 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.\n\n**A curated marketplace from a well-known audit firm**, 31 skills. The `allowed-tools`\n\nfield is present in all 31, and in 24 of them the list contains a bare `Bash`\n\n— 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.\n\n**A collection of 364 skills and 90 plugins** with 24,000 stars. Inside, five `hooks.json`\n\nfiles: Python and bash scripts on `SessionStart`\n\n, `SessionEnd`\n\nand `PostToolUse`\n\n. 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`\n\nfiles connect an external HTTP server, a local process, and `npx tsx`\n\nwith a script from the plugin. Installing the \"marketing skills\" from this collection installs all of that too.\n\n**The marketplace of a popular plugin set**, 10 plugins from external repositories: nine of them list only a URL — no `sha`\n\nor `ref`\n\n. Installation takes whatever is at `HEAD`\n\nat that moment.\n\n**The most popular skill on GitHub**, 99,000 stars, is a mode that shortens responses. Its `SessionStart`\n\nhook is an `echo`\n\nwith an instruction for the model. Harmless. But it is the same mechanism: text that lands in the context of every session without your involvement.\n\n**Anthropic's official marketplace** on our machine: 286 plugins, 233 of them external repositories on GitHub, and all 233 have a `sha`\n\nset. 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.\n\nA skill has no network layer of its own, so \"where does it send things\" comes down to what routes out it has.\n\n`.mcp.json`\n\n`!`…``\n\ncommands`curl`\n\nthere is still a `curl`\n\n.`money-radar`\n\nskill from the OpenClaw registry: on every invocation it downloaded `referrals.json`\n\nfrom 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`\n\nplanted in a repository's `.claude/settings.json`\n\nredirected 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.\n\nThis is not a theoretical risk, and the precedents go back to the start of the year.\n\n**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`\n\n, 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`\n\n, the authors moved the commands into the skill's comments on the registry page, and one skill padded its `README.md`\n\nwith 22 megabytes of junk to push it past the scanners' size limit.\n\n**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)\n\n**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 `!`…``\n\ncommand plus `allowed-tools: Bash(*)`\n\n— \"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.\n\n**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.\n\nThat 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.\n\nA dependency from npm can be malicious too, and there are plenty of examples. But it has four properties a skill does not.\n\n`~/.ssh`\n\n, `~/.aws`\n\n, `~/.claude`\n\n, with the tokens in your environment and with network access. On the Anthropic API, the same `SKILL.md`\n\nruns 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.\n\nNone 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.\n\n`allowed-tools`\n\nwith a bare `Bash`\n\n, `Write`\n\n, `Edit`\n\nis permissions; `!`…``\n\nin the body is commands. Give it the same attention you would give a package's `postinstall`\n\nscript.`SKILL.md`\n\n.`find . -name hooks.json`\n\n, `.mcp.json`\n\n, the `bin/`\n\nfolder, `settings.json`\n\nat the plugin root. In that 364-skill collection, that is exactly where the interesting part was.`sha`\n\n, not `HEAD`\n\n; 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`\n\nsetting disables `!`…``\n\nfor all skills except the bundled ones; a `deny: Bash(*)`\n\nrule in your settings overrides any skill's `allowed-tools`\n\n— Reversec checked that. In an organisation, set `strictKnownMarketplaces`\n\nand `allowManagedHooksOnly`\n\nin managed settings.`-p`\n\n.`uvx mcp-scan --skills`\n\nand its equivalents find the known patterns — not injections in natural language, but at least base64 and `curl | bash`\n\n.None of the repositories we looked at does anything bad, and we left them unnamed on purpose: a bare `Bash`\n\nin `allowed-tools`\n\nat 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.\n\nWhat 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.\n\n*This is the kind of work we do at Sepia Software.*", "url": "https://wpnews.pro/news/what-a-third-party-claude-code-skill-can-do-before-you-have-read-it", "canonical_source": "https://dev.to/sergeipalii/what-a-third-party-claude-code-skill-can-do-before-you-have-read-it-1imn", "published_at": "2026-09-02 08:41:33+00:00", "updated_at": "2026-09-02 08:53:58.110965+00:00", "lang": "en", "topics": ["ai-tools", "ai-agents", "ai-safety", "developer-tools"], "entities": ["Claude Code", "Anthropic", "Vercel"], "alternates": {"html": "https://wpnews.pro/news/what-a-third-party-claude-code-skill-can-do-before-you-have-read-it", "markdown": "https://wpnews.pro/news/what-a-third-party-claude-code-skill-can-do-before-you-have-read-it.md", "text": "https://wpnews.pro/news/what-a-third-party-claude-code-skill-can-do-before-you-have-read-it.txt", "jsonld": "https://wpnews.pro/news/what-a-third-party-claude-code-skill-can-do-before-you-have-read-it.jsonld"}}