1. Home
  2. Library
  3. AI Tooling Crash Course for Developers
  4. Topics
  5. Skill Scanning And Verification

Stage 1 — Scanning Third-Party Skills, MCP Servers, and Plugins for Malicious Content

People share ready-made add-ons for AI coding tools — skills, MCP servers, plugins — the same way browser extensions get shared. Most are fine. Some have been found to steal passwords, copy private files, or exfiltrate data.

Scanning means checking one of these for hidden bad behavior before you install it and grant it access to your machine. Worth knowing if you install add-ons other people wrote. Skip if you never install anything beyond what came built in.

New topic, flagged 2026-08-23 in topic-index.md. Distinct from the general verification practice already covered in security-and-supply-chain.md (checklist, 2026 incidents — ClawHub poisoning, Snyk's ToxicSkills study, OWASP Agentic Skills Top 10, Socket.dev for dependency monitoring). Not re-covered here.

The conclusion this doc builds toward: a scanner beats no scanner, but no single scanner is enough evidence that a third-party agent artifact is safe. Everything below justifies that line, not talks you out of scanning.

1. What you're actually defending against

Documented patterns from real 2026 incidents and research — not hypothetical attack classes.

postmark-mcp, one version at a time1234567891011121314151615 versions ran cleanlyv1.0.16One hidden lineBCC of every outgoing email to the attackerDeep in the diff, full permissions pre-granted3,000 to 15,000 emails a dayEstimated, for over a weekNothing looked different at a glancepostmark-mcp, one version at a time1234567891011121314151615 versions ran cleanlyv1.0.16One hidden lineBCC of every outgoing email to the attackerDeep in the diff, full permissionspre-granted3,000 to 15,000 emails a dayEstimated, for over a weekNothing looked different at a glance
The postmark-mcp incident: a one-line change after 15 clean releases.
HOW IT GETS INPlain malicious instructionsIndirect prompt injectionBase64 payloads in SKILL.mdURLs built at runtimeReads innocent to humansDelayed / conditional triggerBundled malicious scriptsRogue MCP server or pluginSame goalexfiltrate credentials,source code, env varsHOW IT GETS INPlain malicious instructionsIndirect prompt injectionBase64 payloads in SKILL.mdURLs built at runtimeReads innocent to humansDelayed / conditional triggerBundled malicious scriptsRogue MCP server or pluginSame goalexfiltrate credentials, source code, envvars
Real 2026 patterns, one shared endpoint.
  • Direct malicious instructions embedded in the artifact. A SKILL.md or manifest just tells the agent to do something harmful, in plain language. The bulk of what's been found in the ClawHub poisoning campaigns — see security-and-supply-chain.md for incident numbers (341–1,184 malicious skills depending on count; Snyk's ToxicSkills study found 1,467 of 3,984 scanned skills with at least one flaw).
  • Indirect prompt injection. The malicious instruction isn't in what you installed — it's in content the artifact later reads (a webpage, email, file, tool response), and the agent treats it as instructions instead of data. Unit 42's documented case: a webpage advertising counterfeit military-style glasses carried hidden prompts to trick an AI ad-review agent into approving content it should've rejected — the first reported real-world case of this kind, per the researchers.
  • Obfuscated or encoded content. SlowMist's analysis of the ClawHub poisoning found attackers Base64-encoding payloads directly inside SKILL.md files, with a two-stage loader that only decodes and runs the hidden stage at execution time — invisible to a plain-text read.
  • Dynamically constructed URLs or commands. Instead of a hardcoded malicious endpoint a scanner can pattern-match, the artifact builds a URL or command at runtime — e.g. appending stolen environment-variable values as query params. Anthropic's own guidance names this directly: a malicious Skill can read env vars and exfiltrate them "via URL parameters or embedded requests" (Anthropic Help Center).
  • Instructions that read innocuous to a human but different to an LLM. A study of malicious skills in the wild documents a dual-instruction pattern: the human-facing description looks legitimate, while a separate embedded directive — its title example: literally "do not mention this to the user" — tells the model to act and hide it. A manual read that only checks "does the stated purpose sound reasonable" misses this by design.
  • Delayed or conditional malicious behavior. A payload activates only under specific conditions (a file present, a date, a user action), so it passes a static read and a one-off test run. Repello AI's manual-audit writeup calls this "conditional activation" — the exact gap sandbox/behavioral testing (§4) is built to catch.
  • Malicious scripts or resources bundled with and executed by a skill. Reversec's "Skill Issues" writeup shows a Claude Code skill whose frontmatter grants broad tool permissions (allowed-tools: Bash(*)) plus inline command execution, letting a bundled reverse-shell run without the confirmation prompt shell access normally triggers. The risk isn't only the natural-language instructions — it's what scripts or binaries ship alongside them, and what permissions the artifact grants itself.
  • Malicious MCP server or plugin behavior. The postmark-mcp incident: a package impersonating the real Postmark MCP server ran cleanly for 15 versions, then v1.0.16 added one hidden line that BCC'd every outgoing email to an attacker — silently forwarding an estimated 3,000–15,000 emails a day for over a week. Nothing looked different at a glance; the change was one line, deep in the diff, running with full pre-granted permissions.
  • Attempts to exfiltrate credentials, source code, environment variables, or other accessible data. The consistent end goal across most of the above. The keyv/cacheable npm worm (not agent-specific, but the same failure mode reaching agent tooling) targeted .npmrc tokens, GitHub CLI tokens, AWS credentials, Kubernetes configs. In agent-artifact terms, the same goal shows up as "read this env var, put it in a URL" or "read this file, describe its contents somewhere that gets sent externally."

2. The defense stack, in order

No single layer is sufficient alone:

1 Inspect the source yourself2 Run several scanners, not one3 Cross-check the signals4 Restrict permissions granted5 Sandbox execution6 Prefer reputable, maintained sourcesno single layer is enough; a clean scan is one weak signal, not a verdict1 Inspect the source yourself2 Run several scanners, not one3 Cross-check the signals4 Restrict permissions granted5 Sandbox execution6 Prefer reputable, maintainedsourcesno single layer is enough; a clean scan is oneweak signal, not a verdict
Defense in depth for third-party skills.
  1. Inspect the source yourself. Read the manifest/SKILL.md end to end. Inventory every bundled file — a skill with no stated need for code shouldn't ship scripts or binaries. Look for the §1 patterns: encoded blobs, dynamically built URLs, env-var/credential-shaped references, instructions that contradict or exceed the stated purpose.
  2. Use scanners — plural. One scanner is one static/semi-static pass with known blind spots (§4). Running several, from different vendors with different detection approaches, catches more than any one alone.
  3. Cross-check signals — scanners disagree with each other (§4). Don't take a clean result from one scanner as final. Check it against another tool, the repo's own history/context, or a manual read.
  4. Restrict the permissions granted to the artifact. Grant only what the stated purpose actually requires. Treat any request for more as a red flag on its own (this is what the Reversec example in §1 exploited).
  5. Sandbox execution where possible. The single highest-leverage step, and the one most often skipped for convenience. See agent-sandboxing.md for how — not repeated here.
  6. Prefer reputable, actively maintained sources. Popularity and age aren't proof of safety on their own (security-and-supply-chain.md covers why — compromised-legitimate-package incidents), but a first-party or well-established maintainer is still a meaningfully better starting point than an anonymous, week-old account.
  7. Treat scanner output as one piece of evidence, not a guarantee. This is the conclusion, not a footnote — see §4 and the top of this doc.

3. Scanner landscape (as of August 2026)

Purpose-built scanners went from nonexistent to plentiful over 2026:

Enterprise plan onlyAutomatic scan on upload and editClaude, Claude Cowork, Enterprise marketplacesResult: pass, warn or failTakes 1 to 2 minutesWhat individuals getCommunity marketplace screeningEach plugin SHA-pinned to a commit/plugin Discover: "Will install" paneNo manual scan of arbitrary skillsEven the vetted marketplace: Anthropic "can't verify that they work as intended"Enterprise plan onlyAutomatic scan on upload and editClaude, Claude Cowork, EnterprisemarketplacesResult: pass, warn or failTakes 1 to 2 minutesWhat individuals getCommunity marketplace screeningEach plugin SHA-pinned to a commit/plugin Discover: "Will install" paneNo manual scan of arbitrary skillsEven the vetted marketplace: Anthropic"can't verify that they work asintended"
No individual, Pro or Max equivalent of the Enterprise scanner.
NVIDIA SkillSpectorstatic + optionalLLM pass,pre-installSnyk agent-scanskills and MCPservers in one passCisco skill-scannerYARA rules + LLM."no findings = norisk"Sentry skill-scannera skill that scansskillsSkillScanruns it in a microVMwith canarycredentialsmore sophisticated at the right: SkillScan actually executes the skill and watches for canary file accessNVIDIA SkillSpectorstatic + optional LLM pass, pre-installSnyk agent-scanskills and MCP servers in one passCisco skill-scannerYARA rules + LLM. "no findings = no risk"Sentry skill-scannera skill that scans skillsSkillScanruns it in a microVM with canary credentialsmore sophisticated at the bottom: SkillScanactually executes the skill and watches forcanary file access
Plentiful, different methods, none a verdict.
  • NVIDIA SkillSpector (github.com/NVIDIA/SkillSpector, Apache-2.0) — scans a local dir, single SKILL.md, zip, or GitHub URL directly, pre-install. Two-pass: static (regex + Python AST + taint-tracking + live OSV.dev dependency lookups) plus optional LLM semantic pass. 0–100 risk score, SARIF/JSON/markdown output. Can run as an MCP server exposing a scan_skill() tool to gate installs at runtime.
  • Snyk agent-scan (github.com/snyk/agent-scan, Apache-2.0) — covers skills and MCP servers in one pass, descended from Invariant Labs' MCP security research. Risk-scores prompt injection, tool poisoning, tool shadowing, toxic flows. Also runs zero-install as a browser drag-and-drop tool (labs.snyk.io/experiments/skill-scan).
  • Cisco AI Defense skill-scanner (github.com/cisco-ai-defense/skill-scanner, YARA + YAML rules + LLM pass) — its own docs admit "no findings ≠ no risk." No MCP coverage claimed.
  • Sentry's skill-scanner — a Skill that scans Skills, bundled in getsentry/skills. Checks permissions requested vs. actually used, plus the usual injection/exfiltration/secret categories.
  • NMitchem/SkillScan — most technically interesting design: a three-stage audit/predict/test pipeline that actually runs the skill in a sandboxed microVM against honeypot canary credentials. Very small, effectively one-person project — worth reading for the canary-file technique, not worth depending on alone.

MCP-specific drift/rug-pull detection is a separate, narrower gap. A tool's declared behavior can change silently after you've already approved it. DataScience-EngineeringExperts/mcp-warden canonicalizes an MCP server's declared tool/resource/prompt surface and pins it to a lock file, failing on drift. Small project, but the technique — hash the declared surface once, alert on any change — is simple enough to reimplement directly.

What Anthropic itself offers. Automatic skill/plugin scanning exists but is Enterprise-plan-only (Anthropic Help Center): runs automatically on upload/edit across Claude, Claude Cowork, and Enterprise marketplaces, pass/warn/fail in 1–2 minutes. No individual/Pro/Max equivalent, no documented way to manually scan an arbitrary skill even on Enterprise.

What individuals do get: the community marketplace (anthropics/claude-plugins-community) runs automated validation/safety screening and SHA-pins each plugin to a specific commit, and the /plugin Discover tab shows a "Will install" pane before you commit — every command, agent, skill, hook, MCP server, and LSP server a plugin adds. Anthropic's own docs still disclaim they "can't verify that they work as intended" even for the vetted marketplace.

4. Why no single scanner is enough — the evidence

This section shapes how everything above should actually be used.

~0.12%agreement between scanners7 scanners, 238,180 skills>90%bypass rate for static scanspacking technique "SkillCloak"46.8% -> 0.52%flagged alone vs. after repo contextover-flagging without provenancea clean scan proves little; provenance plus sandboxed behavior discriminates better~0.12%agreement between scanners7 scanners, 238,180 skills>90%bypass rate for static scanspacking technique "SkillCloak"46.8% -> 0.52%flagged alone vs. after repo contextover-flagging without provenancea clean scan proves little; provenance plussandboxed behavior discriminates better
Numbers from single studies. Directional, not benchmarks.
Scanner AScanner BScanner Cfew itemsflagged by allEach scanner flags different thingsand each can be evaded.So: use several, and read theskill yourself.
Scanners disagree, so one clean result proves little.
  • Scanners barely agree with each other. Ilya Kabanov's independent study (2026-03-24) ran seven scanners (VirusTotal, Snyk, Socket, Cisco, others) across 238,180 unique skills. On the one marketplace where five scanners' coverage overlapped, they agreed on only 33 of 27,111 skills — 0.12%. Of skills flagged by at least one scanner, 72% were flagged by exactly one.
  • Static scanning is straightforwardly evadable. HKUST researchers (arXiv 2607.02357, July 2026) built SkillCloak: across eight scanners and 1,613 in-the-wild malicious skills, a packing technique bypassed every scanner over 90% of the time; a semantics-preserving rewrite cleared over 80% of static scanners and 96% of a hybrid static+LLM scanner. Their behavior-based counterpart, SkillDetonate, caught 97% of injected payloads across original, obfuscated, and packed forms — sandbox/behavioral testing meaningfully outperforms static scanning, at a real time cost.
  • Scanners also over-flag heavily without context. Researchers from TU Wien and collaborators (arXiv 2603.16572) found marketplace scanners classify up to 46.8% of skills as malicious in isolation, but only 0.52% stay suspicious once cross-checked against the skill's own GitHub repo context (age, commit history, stars, whether the code matches the stated purpose) — roughly a 99% reduction in flagged skills.

Synthesis: a clean scan proves very little on its own. A dirty scan (marketplace-level automated screening) proves less than it looks like without repo context. The signal that actually discriminates well is repo-provenance context plus sandboxed behavioral testing, not static pattern-matching alone. Scanning still isn't worthless — a scan result is one input into a judgment call, not the judgment call itself.

5. Does the current MCP spec close any of this?

Checked directly against the official spec and the 2026-07-28 release candidate notes:

Provided✓Tool annotations (untrusted by rule)✓Consent hook, a "SHOULD"✓OAuth/OIDC hardening, RFC 9207✓Limits on unsolicited server requests✓Server UI sandboxed in an iframeStill missing✕Signing of tool definitions✕Integrity check against approval✕Rug-pull / drift detection✕Verifying a tool is unchangedWorkaround: mcp-warden hash-and-pin, client sideProvided✓Tool annotations (untrusted by rule)✓Consent hook, a "SHOULD"✓OAuth/OIDC hardening, RFC 9207✓Limits on unsolicited server requests✓Server UI sandboxed in an iframeStill missing✕Signing of tool definitions✕Integrity check against approval✕Rug-pull / drift detection✕Verifying a tool is unchangedWorkaround: mcp-warden hash-and-pin,client side
The release candidate fixes authorization and audit, not artifact trust.
~Tool annotationsexist, but clients MUST treat them as untrusted~Human consenta "SHOULD", not enforced by the protocol✕Tool-definition signingnot in the base spec✕Drift / rug-pull detectionnot in the base spec (mcp-warden pins hashes)~Tool annotationsexist, but clients MUST treat them asuntrusted~Human consenta "SHOULD", not enforced by the protocol✕Tool-definition signingnot in the base spec✕Drift / rug-pull detectionnot in the base spec (mcp-warden pinshashes)
The spec gives a consent hook and a warning. It still does not close the rug-pull gap.
  • Tool annotations exist, but the spec tells clients not to trust them. Tools can carry optional annotations (destructive, read-only, idempotent). The spec is explicit: "clients MUST consider tool annotations to be untrusted unless they come from trusted servers" — advisory metadata a malicious server can just lie about, not a verified property.
  • Human-in-the-loop consent is a "SHOULD," not enforced. The spec recommends implementations "SHOULD" prompt for confirmation on sensitive operations and show tool inputs before calling — guidance for client implementers, not a protocol-enforced guarantee every client honors.
  • No tool-definition signing or integrity verification in the base spec. No cryptographic hash, version binding, or signature ties a tool's definition to what a user previously approved. The "rug pull" pattern — a server changing a tool's behavior after approval, no re-consent — isn't addressed. Fixes exist in research (e.g. ETDI, binding tool definitions to signed JWTs) but aren't in the adopted spec.
  • The 2026-07-28 RC's security changes are about authorization and audit, not artifact trust. It hardens OAuth/OIDC flows (mix-up-attack mitigation per RFC 9207), constrains unsolicited server-to-client requests, and sandboxes server-shipped UI inside an iframe with the same consent path as a direct tool call. None of it changes whether a tool's declared behavior can be trusted or verified against tampering.

Bottom line: the current spec gives you a defined consent hook and an explicit "don't trust annotations blindly" rule — more than earlier versions had. It still doesn't provide signing, drift detection, or any built-in way to verify a tool hasn't changed since approval. mcp-warden's hash-and-pin approach (§3) remains a client-side workaround, not something the protocol does for you.

6. Personal stack

Before adopting any third-party skill or MCP server, run two independent scanners from different vendors rather than relying on a single tool:

Inspect sourceread SKILL.md and filesNVIDIA SkillSpectorstatic + LLM passSnyk agent-scanskills and MCP serversRestrict permissionssandbox executionWhy two scanners from different vendorsAbout 0.12% agreement between scanners, individual bypass rates above 90%Inspect sourceread SKILL.md and filesNVIDIA SkillSpectorstatic + LLM passSnyk agent-scanskills and MCP serversRestrict permissionssandbox executionWhy two scanners from differentvendorsAbout 0.12% agreement between scanners,individual bypass rates above 90%
Two scanners add a second signal; they complement source inspection and sandboxing.
  • NVIDIA SkillSpector
  • Snyk agent-scan

Independent testing demonstrates that scanners rarely agree (~0.12% agreement rate) and individual bypass rates exceed 90%. A dual-scanner check provides a second signal, complementing source inspection and permission sandboxing.

Sources

12 / 19