Topic: claude code audit skill
Claude Code: audit a Skill — manifest, handlers, and what changes vs an MCP server
"Claude Code audit skill" is the inverse phrasing of the rest of this page cluster — the searcher is asking how to audit a skill they're using or shipping in Claude Code's Skills format specifically. That format has a manifest, declared capabilities, in-process handlers, and a different protocol-compatibility surface than a remote MCP server. The audit changes accordingly. This page names what's different, what's the same, and how the SkillAudit engine handles each.
TL;DR
A Claude Code Skill is the file-format unit Anthropic ships for in-CLI extensions: a directory containing a SKILL.md manifest plus optional handler scripts, declaring capabilities the agent can invoke. Auditing one means checking (a) manifest scope — declared permissions vs what the handlers actually use, (b) handler safety — the same SSRF/credentials/exec/deserialization classes that apply to MCP, (c) prompt-injection susceptibility — handlers that pull external content, (d) protocol compatibility — version pin and skill-format compliance. SkillAudit accepts a Skill directory as a ZIP upload or via a GitHub URL; the engine adapts its rule pack to the in-process shape and runs the same six-axis grade as for MCP servers. ~60s pass-time, free for public repos. Run an audit.
Two intents on the same query — both addressed
"Claude Code audit skill" parses two ways:
- "Audit my Claude Code Skill" — the searcher wrote a Skill (or installed one from a community source) and wants the security/quality signal before publishing or before letting it run in their agent. Primary intent for this page.
- "A Claude Code skill that performs auditing" — the searcher is looking for a Skill they can install into Claude Code that audits their code. We ship one of these too —
skillaudit/cc-audit-skillwraps the public scanner soclaudecan invoke it on a path. Linked at the end of this page.
Most of this page covers intent 1. Intent 2 is the small section at the end — the Skill is a thin wrapper, not the page's main subject.
What's different about a Claude Code Skill vs a remote MCP server
Both are agent-extensible surfaces, but the threat model and the audit shape differ in ways that matter:
| Property | MCP server (remote) | Claude Code Skill (in-process) |
|---|---|---|
| Process boundary | Separate stdio/HTTP process | Runs in the agent's process / shell context |
| Capability declaration | Tool definitions registered at startup | SKILL.md manifest + frontmatter |
| Permission scope | OAuth scopes, env vars | File-system root, allowed binaries, network |
| Execution model | JSON-RPC tool calls | Direct function/script invocation by agent |
| Failure blast radius | Token exfil + reachable APIs | Local FS, shell, dev environment |
| Audit emphasis | Tool argument tainting → fetch/exec sinks | Manifest scope drift + handler taint + shell shape |
| Prompt-injection concern | Tool returns external content to model | Skill instructions + agent files mixed in same context |
| Re-audit cadence trigger | Server bump, model retrain | SKILL.md edit, handler edit, claude-code version bump |
In practice: a Skill audit weights the manifest-scope axis higher because a Skill running in your shell with broad scope is closer to "trust me with your laptop" than a remote MCP server with a network-bounded scope.
The four things a Claude Code Skill audit specifically checks
1. Manifest scope vs handler reality
The SKILL.md frontmatter declares what the Skill can do — typically allowed file roots, allowed shell commands, network endpoints, and any required environment variables. The audit compares the declared shape to what the handler scripts actually do. Three classes of finding:
- Drift — broader than needed. Manifest declares
shell: any; handlers only ever invokegitandnode. Failure: scope unjustified by usage. - Drift — narrower than declared, but the handler reaches further. Manifest declares
fs: read-only ./reports; handler writes to./on a particular branch. Failure: the manifest under-declares and the runtime would either block or silently elevate, depending on the host. - Manifest claims "no network" but the handler imports a library that fetches. Indirect — covered by a dependency-tree pass plus AST scan on imports.
This is the highest-leverage axis for a Skill audit. The MCP-server analogue (OAuth scope drift) is lower-leverage because the OAuth provider enforces some of it; in the Skill case, the only enforcer is the host runtime, and it's permissive by design.
2. Handler safety — the seven static classes
The handler scripts (Bash, Node, Python, depending on the Skill) get the same static taint pass as MCP server tool handlers, slightly remapped for the in-process shape:
- Command exec — handlers that template untrusted input (agent-supplied arguments, file contents from a tool-fetch) into shell strings. Most common F-grade pattern in Skill audits because Skills are shell-shaped by default.
- SSRF — same shape as in MCP servers, just at a slightly lower prevalence because not every Skill is network-shaped. Still 25–30% of the corpus we've seen.
- Credential exposure — env-var reads in handler scripts that echo into agent context, plus shell scripts that
echo $TOKENat any log level. - Unsafe file-system access — path traversal in handlers that take a path argument, write-anywhere shapes, symlink follows that escape the declared root.
- Unsafe deserialization — same shape, lower prevalence.
- HTML/markdown sink leaks — for Skills that emit rendered output. Usually low risk; flagged for completeness.
- Sensitive-binary invocation — Skill-specific class. Handlers that invoke
curlwith attacker-controlled URLs,git pushto attacker-controlled remotes,npm installfrom attacker-controlled registries. Maps to "command exec" structurally but with a higher-trust default — the binary itself is trusted, the argument isn't.
3. Prompt-injection susceptibility
For a Skill that reads external content (web pages, files outside the declared root, RSS, third-party APIs) and surfaces it back to the agent, the same prompt-injection probe bank from the MCP-server audit applies. The threat model is slightly different — the Skill instructions and the agent's own conversation share the same context window, and an injected instruction can hijack subsequent agent actions across other Skills. We probe the live Skill in a sandboxed Claude Code environment with the same 14-probe bank used against MCP servers; the susceptibility band is reported on the security axis the same way.
4. Protocol / Skill-format compatibility
The Claude Code Skills format versions; format-breaking changes have happened in the past and will happen again. A Skill that "works" on the current claude-code release can fail to load on the next minor version if the manifest schema tightens. The audit checks: SKILL.md matches current schema, declared claude-code version range is sane (not pinned to one patch, not unbounded), handler-script shebangs and runtimes are present in the declared environment. This is the analogue of the client-compatibility axis on the MCP-server side; on Skills it's tighter because the host is just claude-code, not four clients.
How SkillAudit handles a Claude Code Skill input
- Input formats accepted. A GitHub URL pointing at a Skill repo, an uploaded ZIP of the Skill directory, or a path inside a monorepo. The engine detects the Skill shape from the presence of
SKILL.mdat the root. - Manifest parse. The frontmatter and body of
SKILL.mdare parsed; declared scopes and capability shape feed the manifest-vs-handler diff. - Static pass. The same tree-sitter rule pack runs against handler scripts, with the seven Skill-class subset enabled. Bash handlers go through a Bash-specific rule pack (a smaller set than the JS/Python ones because Bash has fewer safe-by-construction call shapes; we lean on
shellcheck-style heuristics plus our own taint rules). - Sandbox boot + LLM probe. The Skill loads in a sandboxed claude-code instance with stubbed env and recorded network. The probe bank runs against any handlers that match the susceptible-shape predicate. Pass-time slightly higher than MCP-server audits (60–120s vs 30–90s) because Skill boot is heavier than MCP-server stdio boot.
- Grade. The same six-axis A–F. The manifest-vs-handler diff feeds the permissions-hygiene axis, weighted higher than for MCP servers per the threat-model table above.
- Output. Public report page + embeddable badge + remediation hints per finding. Same artifact shape as MCP-server audits; same Pro/Team plan structure for private Skills and CI gates.
Common F-grade patterns in Claude Code Skills
From the Skills we've audited so far, the F-grade patterns cluster:
- Manifest declares
shell: anyfor convenience. Even if the handler is tight, the declared scope says "anything goes" — which a buyer scanning manifests treats as a yellow flag and a Skill audit treats as a finding. Tighten to the actual binary set. - Handler script uses
$1directly in a shell pipe. Bash handler that runsgit log --grep "$1"with no quoting and no validation. Trivially exploitable if the agent passes a string with backticks. The fix is quoting + validation, not a more clever pipe. - Skill writes to
~/by default, not to a Skill-local directory. A Skill that "saves analysis output" to~/Documents/when the declared FS root is./.skill-output/. Catches up to the user the first time the Skill is run on a different machine where~/Documentsdoesn't exist or is symlinked elsewhere. - Skill calls
curl | bashin setup. Self-explanatory. We grade this F on the security axis with no escape hatch — the pattern is unsafe regardless of the URL being fetched. - SKILL.md frontmatter missing required fields. Skill versioning,
claude-codeversion range, declared author. Documentation/maintenance axis hits.
Patches for each of these are mechanical — typically one to five lines. The most leveraged fix is tightening the manifest shell declaration to a closed set; that one change usually moves a manifest-axis grade from D/F to B.
Intent 2: a Claude Code Skill that performs auditing
If you arrived here looking for a Skill you can install into Claude Code that wraps SkillAudit so claude can audit a path, that's skillaudit/cc-audit-skill — install via claude plugin install skillaudit/cc-audit-skill (subject to availability — the Skills marketplace is rolling out). The Skill exposes /skillaudit <path-or-url>; output is the same report as the web flow, rendered in your terminal. Source is on GitHub; it self-audits on every release (the report is in the README). For most authors auditing their own Skills this is a faster loop than uploading a ZIP — but the public badge embed comes from the web side either way.
Where this page sits in the cluster
This page is the format-specific take. Two siblings cover adjacent intents:
- Claude skill auditor — the broader role, six axes. Covers both Skills and MCP servers; start here if you don't know which format applies.
- Claude skill security audit — the security-only lens, the eight finding classes. Covers both Skills and MCP servers; sharper if you only want the threat-surface answer.
Related questions
Is a Skill audit different from an MCP server audit?
Yes — same six axes, different weighting and a couple of swapped-in classes. The biggest delta is the manifest-vs-handler diff, which is the highest-leverage axis on Skills and a smaller axis on MCP servers. The static rule pack overlaps about 80% with the MCP-server pack; the LLM-probe bank is the same.
Can I audit a Skill before it's published?
Yes — upload as a ZIP or point to a private GitHub repo on the Pro plan. The audit doesn't require the Skill to be in any registry; pre-publish is the most common audit shape we see for Skills.
Does the audit work on Skills that aren't open source?
If you have the source, yes — Pro plan, private repo or ZIP upload. If you only have the installed binary/installed Skill directory and not the source, partial — the manifest pass works, the static pass doesn't on minified/compiled handlers. For closed-source Skills the right answer is usually to ask the author for the source or to use a different Skill.
Why is "shell: any" auto-flagged?
Because the entire point of declaring scope is to bound the blast radius. shell: any says "this Skill can run any binary on the user's machine"; even if the handler today only runs git, the manifest contract is an unbounded one. Tightening to a closed set (e.g. shell: [git, node, npm]) is a one-line fix that moves the grade.
How do I wire a Skill audit into CI?
Same as the MCP-server flow — use the GitHub Action. The action auto-detects Skill vs MCP-server shape and runs the appropriate rule pack. Configure a minimum-grade gate (we recommend B for Skills given the in-process blast radius, vs B for MCP servers). Wiring details.
What about Skills written in languages SkillAudit doesn't statically support?
The static layer covers TypeScript, JavaScript, Python, and Bash today. Skills in Go, Rust, or shell-other-than-Bash get partial coverage — the manifest pass and the LLM-probe pass run; the static pass is skipped with a warning. A finding from the manifest or the probe is still a finding; the absence of static findings shouldn't be read as "the static layer would have found nothing." Coverage roadmap in the methodology page.
Further reading
- Claude skill auditor — the broader role, six axes, what an auditor isn't.
- Claude skill security audit — the security-only lens, eight finding classes.
- MCP server security best practices — many of the 12 rules apply to Skills with minor remapping.
- MCP server security testing — the test-type-by-finding-class playbook.
- MCP server security scanner — the technical surface a scanner has to detect.
- MCP server security tools — where each tool fits in the landscape.
- Anatomy of a credential leak — applies to Skills with one remapping (env in tool handler → env in handler script).
- The state of MCP server security, 2026 — methodology and grade distribution.
- Engine v0.3 methodology — full rule pack, including the Skill-specific subset.
- All public audits — the corpus.