DepWall

Home / Blog

  • ai agents
  • plugins
  • code execution
  • measurement

Enabling a plugin is code execution, before you type anything

A plugin's SessionStart hook runs on startup, on /clear and on compaction. There is no install to gate and no prompt. We measured 66 real manifests to find out what the honest shape looks like.

An install-time gate has one structural blind spot, and it is the obvious one: it can only act when something is being installed. Agent plugins slip under that.

A plugin can register hooks against agent events. SessionStart fires on startup, on /clear, and on compaction. So enabling the plugin is the trigger — no install to intercept, no prompt, nothing to approve. That makes it strictly more dangerous than a SKILL.md, which at least needs the agent to choose to read it.

What the manifests actually look like#

We built the check against the plugins installed on a real machine rather than against the documentation, and two details came out of that which the docs would not have given us.

Hook filenames are not consistent. Across 66 manifests: hooks.json, claude-codex-hooks.json, hooks-cursor.json, copilot-hooks.json. Matching the conventional name alone would have missed three of those four.

A manifest's "hooks" is often a string, not an object — a path to another file. That has to stay silent, because the manifest itself runs nothing; the file it points at is what matters, and that gets checked on its own path.

Sibling runtimes ship side by side too: .claude-plugin, .codex-plugin and .devin-plugin in one repository, each with its own plugin.json.

The benign shape, and why it is also the evasion#

Legitimate plugin hooks look like this:

bash "${CLAUDE_PLUGIN_ROOT}/hooks/session-guard.sh"

Guarded on the plugin root, running a script from inside its own directory, touching no network. Across all 66 manifests, zero were flagged.

Which means the honest thing to say is that an attacker writes exactly that line and puts the payload in the .sh. The manifest reads clean by inspection.

It is narrower than it sounds — a repository scan does collect and judge the shell script, because .sh files are scored into it. The gap is the write-time hook, which sees only the file being written. We publish that rather than leave you to find it.

What a scanner should refuse to do here#

Our first version of the path check matched any hooks/*.json. A React project's src/hooks/index.json would have been claimed — and since an unparseable file returns a warning, that is a false prompt on somebody's ordinary source tree. The filename has to say hooks too.

Everything here is capped at ASK, never BLOCK. It is a text read of a configuration nobody has executed, and a false block on somebody's own plugin is how a gate gets uninstalled.

The general point#

Agents have grown several ways to run code that never pass through a package manager: editor auto-run configs, plugin hooks, skill helpers. None of them is an install. All of them execute because a file exists and an event happened.

If your supply-chain thinking stops at npm install, that is the whole surface you are not looking at.

About DepWall

An install-time firewall for AI coding agents. It sits in front of npm, pip, cargo, go and the rest, and decides whether a package is safe to pull before any of its code runs. Free and open source.

Install it · What it does · Red-team corpus

Related