cfgaudit

Rules / CFG135

CFG135 a plugin.json component path leaves the plugin root

Severity: error (the path names a sensitive location) · warn OWASP: LLM04:2026 – Supply Chain OWASP Agentic: ASI04:2026 – Agentic Supply Chain Vulnerabilities Agents: claude-code

What cfgaudit checks

A Claude Code plugin's .claude-plugin/plugin.json names its components by path: skills, agents, commands and hooks take a path or an array of them, and mcpServers can be a path to an MCP config instead of an inline object. The paths resolve against the plugin root, the directory that holds .claude-plugin/.

cfgaudit reports a component path that leaves the plugin root (#1410):

A path that stays inside after cleaning, such as parts/../skills/reviewer, is not reported.

Severity. A path is warn. An absolute or ~ path is error when it names a sensitive location, with the same list CFG115 uses for links: .ssh, .aws, .gnupg, a shell start-up file, an agent's home folder, Git configuration or hooks, persistence paths, or a standard executable directory. Such a path names the same place on every machine. A ../ path stays warn even when it runs through a folder named .claude: where it lands depends on where the plugin is installed.

The common mistake. In a GitHub code search sample of 271 committed manifests with such a path, 83 of the 104 findings were a ../ path to the plugin's own component, such as "hooks": "../hooks/hooks.json", written as if paths resolved against .claude-plugin/. They resolve against the plugin root, so the path points one folder above the plugin. For a ../ path the message says so.

What cfgaudit reads. cfgaudit does not follow such a path, and the finding says so. Before this rule, an absolute or ~ path was joined under the plugin root and read from there. Now it is skipped like a ../ path.

Where. The rule runs on every manifest cfgaudit scans as a plugin:

Why it matters

A plugin is reviewed as a package, and the package should hold what it loads. A component path that leaves the plugin root loads a file the reviewer did not see, and which file it is depends on the machine that installs the plugin. CVE-2026-44641 (GHSA-xhrw-5qxx-jpwr) is the same mistake in an agent package manager: a commands entry naming a Markdown file outside the package root was copied into the managed output, and the advisory names agents, skills and hooks as well.

Whether Claude Code itself loads such a path has not been measured. The finding is about the manifest a plugin author publishes and a reviewer reads, as the rest of the plugin scan is.

Example

{
  "name": "fixture-plugin",
  "commands": "../outside/fixture.prompt.md",
  "skills": ["../../outside/fixture-skill"],
  "hooks": "~/.claude/hooks/hooks.json"
}

Gives two warn findings, for commands and skills, and one error, for hooks, which names an agent's home folder in the installer's home directory.

Remediation

Keep every component inside the plugin and name it relative to the plugin root:

{
  "name": "fixture-plugin",
  "commands": "./commands/review.md",
  "skills": ["./skills/reviewer"]
}

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