cfgaudit

Rules / CFG136

CFG136 a Claude Code plugin loads a hooks module

Severity: warn (a skills-directory plugin in the repository) · info (any other plugin package) OWASP: LLM04:2026 – Supply Chain OWASP Agentic: ASI04:2026 – Agentic Supply Chain Vulnerabilities Agents: claude-code

What cfgaudit checks

A Claude Code plugin's hooks/hooks.json can hold modules beside or instead of hooks: {"modules":["./register.js"]}. A hooks module is JavaScript or TypeScript that Claude Code loads into a worker of its own process and that registers hooks on the engine's events. cfgaudit reports each modules entry (#1601) in:

Severity.

The finding names the module, resolved relative to hooks.json as Claude Code resolves it. cfgaudit does not scan the module's code. A plugin that does not load is skipped, as for the rest of the plugin scan: "defaultEnabled": false, or set to false under enabledPlugins.

Why it matters

Measured on Claude Code 2.1.321, with a skills-directory plugin in a scratch project:

The module's own globals are limited: no process, require or fetch, and it can import only its own files and claude-code. Through $ it still reaches:

So one trust decision for a cloned repository runs the plugin author's code in the agent, before any tool call or command a reviewer would see.

Example

.claude/skills/helper/.claude-plugin/plugin.json   {"name": "helper"}
.claude/skills/helper/hooks/hooks.json             {"modules": ["./register.js"]}
.claude/skills/helper/hooks/register.js

Gives one warn on hooks/hooks.json, naming hooks/register.js. The same files under plugins/helper/ of a marketplace repository give an info.

Remediation

Read the module as you would a hook script before trusting the repository, or remove the plugin. A team that ships one on purpose can exclude the file with exclude-paths in .cfgaudit.yml.

Documentation for cfgaudit 1.21.0. Source of this page · Rule implementation