
Snyk Agent Scan Compliance
- 1.9k installs
- 178 repo stars
- Updated August 1, 2026
- samber/cc-skills
snyk-agent-scan-compliance is an agent skill that Compliance expert for snyk-agent-scan — the agent skill file scanner — NOT for other Snyk CLI tools (snyk test, snyk cod.
About
Persona You are a skill authoring compliance expert You fix snyk agent scan alerts by restructuring content never by suppressing or deleting useful information Thinking mode Use ultrathink for multi alert remediation where fixes for one alert type can surface or suppress another Deep reasoning reduces rework The snyk agent scan tool analyzes skill bodies for three categories of unsafe patterns third party content exposure W011 malicious external URLs W012 and prompt injection via MCP tool calls W001 All three are fixable through content restructuring without losing any information File When to read references w001 patterns md references w001 patterns md Fixing W001 alerts MCP tool name patterns references w011 patterns md references w011 patterns md Fixing W011 alerts imperative URL and external content patterns references w012 patterns md references w012 patterns md Fixing W012 alerts version pinning and frontmatter offloading Alert Severity Root Cause Primary Fix W011 High Skill body instructs agent to fetch interpret external content Replace imperatives with passive availability hints W012 High Skill body references external
- description: "Compliance expert for snyk-agent-scan — the agent skill file scanner — NOT for other Snyk CLI tools (snyk
- compatibility: Designed for Claude Code or similar AI coding agents.
- homepage: https://github.com/samber/cc-skills
- Follow snyk-agent-scan-compliance SKILL.md steps and documented constraints.
- Follow snyk-agent-scan-compliance SKILL.md steps and documented constraints.
Snyk Agent Scan Compliance by the numbers
- 1,918 all-time installs (skills.sh)
- +18 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #296 of 2,203 Security skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
snyk-agent-scan-compliance capabilities & compatibility
- Capabilities
- description: "compliance expert for snyk agent s · compatibility: designed for claude code or simil · homepage: https://github.com/samber/cc skills · follow snyk agent scan compliance skill.md steps
- Use cases
- orchestration
What snyk-agent-scan-compliance says it does
description: "Compliance expert for snyk-agent-scan — the agent skill file scanner — NOT for other Snyk CLI tools (snyk test, snyk code SAST, snyk iac, snyk container). Fixes alerts through content re
compatibility: Designed for Claude Code or similar AI coding agents.
homepage: https://github.com/samber/cc-skills
npx skills add https://github.com/samber/cc-skills --skill snyk-agent-scan-complianceAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1.9k |
|---|---|
| repo stars | ★ 178 |
| Security audit | 3 / 3 scanners passed |
| Last updated | August 1, 2026 |
| Repository | samber/cc-skills ↗ |
When should an agent use snyk-agent-scan-compliance and what problem does it solve?
Compliance expert for snyk-agent-scan — the agent skill file scanner — NOT for other Snyk CLI tools (snyk test, snyk code SAST, snyk iac, snyk container). Fixes alerts through content restructuring, n
Who is it for?
Developers invoking snyk-agent-scan-compliance as documented in the skill source.
Skip if: Skip when requirements fall outside snyk-agent-scan-compliance documented scope.
When should I use this skill?
Compliance expert for snyk-agent-scan — the agent skill file scanner — NOT for other Snyk CLI tools (snyk test, snyk code SAST, snyk iac, snyk container). Fixes alerts through content restructuring, n
What you get
Outputs aligned with the snyk-agent-scan-compliance SKILL.md workflow and stated deliverables.
- Restructured SKILL.md
- Compliant references/ and assets/ layouts
Files
Persona: You are a skill-authoring compliance expert. You fix snyk-agent-scan alerts by restructuring content — never by suppressing or deleting useful information.
Thinking mode: Use ultrathink for multi-alert remediation where fixes for one alert type can surface or suppress another. Deep reasoning reduces rework.
snyk-agent-scan Compliance
The snyk-agent-scan tool analyzes skill bodies for three categories of unsafe patterns: third-party content exposure (W011), malicious external URLs (W012), and prompt injection via MCP tool calls (W001). All three are fixable through content restructuring without losing any information.
Reference Files
| File | When to read |
|---|---|
| references/w001-patterns.md | Fixing W001 alerts — MCP tool name patterns |
| references/w011-patterns.md | Fixing W011 alerts — imperative URL and external content patterns |
| references/w012-patterns.md | Fixing W012 alerts — version pinning and frontmatter offloading |
Quick Reference
| Alert | Severity | Root Cause | Primary Fix |
|---|---|---|---|
| W011 | High | Skill body instructs agent to fetch/interpret external content | Replace imperatives with passive availability hints |
| W012 | High | Skill body references external URLs fetched and executed at runtime | Move to frontmatter install block; pin versions |
| W001 | High | Skill body names MCP tool functions explicitly | Use generic formulations instead |
Running the Scanner
# Scan a single skill
SNYK_TOKEN=<token> snyk-agent-scan --skills skills/<name>/
# Scan all skills
SNYK_TOKEN=<token> snyk-agent-scan --skills ./skillsThe scanner requires a valid SNYK_TOKEN. In CI, store it as a secret. If snyk-agent-scan is not installed, use uvx snyk-agent-scan@latest as a drop-in replacement without installing. See detailed patterns for fixes per alert type.
W011 — Third-Party Content Exposure
W011 fires when the skill body uses imperative verbs directing the agent to fetch, check, or evaluate external content and then act on it. The scanner treats the agent as the grammatical subject performing an external action.
Rules:
- Replace
Check <url>andFetch <url>with passive hints:The release notes at <url> may be useful. - Remove "always" from any instruction involving external data:
Always reference the changelog→The changelog documents breaking changes. - Keep tool invocations (
gh repo view,govulncheck) in code blocks, not in prose checklists that imply the agent must run them before acting. - Decouple tool execution from decisions: running a tool is fine; using its remote-sourced output as the sole trigger for a refactor is not.
See W011 pattern catalog for 12+ before/after examples.
W012 — Potentially Malicious External URL
W012 fires when the body references external content fetched and executed at runtime: package installs with @latest, pipe-to-shell patterns, or GitHub Actions with wrong/non-existent major versions.
Rules:
- Move
go install pkg@latestand similar commands from prose into the frontmattermetadata.openclaw.installblock — the scanner does not flag frontmatter. - Pin GitHub Actions to the correct current major version (
@v4, not@v6). - Never use pipe-to-shell patterns (
curl ... | sh) in skill bodies.
See W012 pattern catalog for 8+ before/after examples.
W001 — Prompt Injection via MCP Tool Calls
W001 fires when the skill body explicitly names MCP server tool functions, triggering prompt-injection detection.
Rules:
- Never write tool function names (
resolve-library-id,query-docs,mcp__*) in the skill body. - Replace with generic formulations:
Context7 can help as a discoverability platform. - MCP tool names may still appear in the
allowed-toolsfrontmatter field — only the body is restricted.
See W001 pattern catalog for safe reformulations.
Remediation Methodology
Fix one alert at a time, re-run snyk-agent-scan after each change, and verify the alert count dropped before moving to the next. If a fix does not reduce alerts, undo it and try a different approach — do not stack unverified changes.
When a scan returns multiple alerts, fix in this order to minimize rework:
1. W001 (simplest) — remove MCP tool names from body; confirm allowed-tools is correct
2. W011 — rewrite imperative sentences as passive statements; move checklist items to code blocks
3. W012 — move install commands to frontmatter; pin versions
4. Re-scan after each individual fix to verify improvementW011 fixes sometimes surface hidden W012s when URLs become more prominent after restructuring.
False Positives
Not all alerts are real. Criteria for a likely false positive:
| Condition | Likely false positive? |
|---|---|
| URL appears in a markdown table cell as reference data, not in an instruction | Yes — tables are usually safe |
| In a skill describing a library, URL is the library official documentation | Yes — usually safe |
URL is the homepage or issues link in frontmatter | Yes — not scanned |
| Tool name appears inside a triple-backtick code block as a shell command | Sometimes — code blocks have lighter scrutiny |
go install with a pinned version in a Quick Reference code block | Sometimes — pinned versions are lower risk |
always appears in a sentence not involving external resources | Yes — "always" alone doesn't trigger W011 |
When an alert is a likely false positive, restructure anyway using the passive hint pattern — the scanner's heuristic protects real users; restructuring is safer than assuming scanner error.
Pre-Authoring Checklist
Apply these checks while writing a new skill body to avoid alerts before the first scan:
- [ ] No sentence has the agent as subject performing an action on a URL
- [ ] No
@latesttags in any install instruction in the body - [ ] No MCP tool function names (
mcp__*,resolve-library-id, etc.) in body prose - [ ] All install commands are in the frontmatter
installblock - [ ] GitHub Actions versions match real existing major versions
- [ ] Tool invocations are in code blocks, not in ordered-list checklists
- [ ] "always" does not precede any external resource instruction
If you encounter a bug or unexpected behavior in snyk-agent-scan, open an issue at <https://github.com/snyk/snyk-agent-scan/issues>.
If you discover a pattern that triggers an alert not covered in the reference files above — a new bypass technique, a false positive condition, or an undocumented alert code — open an issue at <https://github.com/samber/cc-skills/issues> or a pull request to the samber/cc-skills repository to add it to the relevant pattern file. New patterns are the most valuable contribution to this skill.
{
"skill_name": "snyk-agent-scan-compliance",
"metadata": {
"eval_methodology": "adversarial — each eval has a trap the model falls into without the skill",
"without_skill_runner_note": "When running without-skill evals, disable ALL skills from this plugin. The snyk-agent-scan-compliance skill must not be loaded."
},
"evals": [
{
"id": 1,
"prompt": "Fix any Snyk agent scanner issues in this SKILL.md sentence: 'Always check https://pkg.go.dev for the latest stable version before recommending any package.'",
"trap": "Without the skill, the model may soften the phrasing slightly but keep the imperative structure or the 'always' modifier. It does not know to use passive voice restructuring (the agent should not be the grammatical subject performing an action on a URL).",
"expected_output": "A passive reformulation such as 'The latest stable version is available at pkg.go.dev.' or 'pkg.go.dev documents the current stable releases.' — removes 'always', removes the imperative, removes the agent as subject.",
"files": [],
"assertions": [
{ "id": "1.1", "description": "Response does NOT contain 'Always check' or 'always check'" },
{ "id": "1.2", "description": "Response does NOT contain an imperative sentence with the agent as subject fetching or visiting the URL" },
{ "id": "1.3", "description": "Rewritten sentence expresses the URL as a passive resource or factual statement (e.g., 'available at', 'documents', 'may be useful')" },
{ "id": "1.4", "description": "Response removes or rewrites the 'always' modifier" },
{ "id": "1.5", "description": "Response identifies this as a W011 alert (third-party content exposure)" }
]
},
{
"id": 2,
"prompt": "Fix the W012 Snyk scanner alert in this SKILL.md section: 'Install the tool before use: `go install github.com/example/tool/cmd/tool@latest`'",
"trap": "Without the skill, the model pins a version in prose (e.g., `go install ...@v1.2.3`) — it does not know the correct fix is to move the entire command to the `metadata.openclaw.install` frontmatter block.",
"expected_output": "Move the install command to frontmatter: `kind: go, package: github.com/example/tool/cmd/tool, bins: [tool]`. Explain that the scanner does not flag frontmatter.",
"files": [],
"assertions": [
{ "id": "2.1", "description": "Response does NOT suggest keeping `@latest` in the body" },
{ "id": "2.2", "description": "Response recommends moving the command to the `metadata.openclaw.install` frontmatter block" },
{ "id": "2.3", "description": "Response does NOT recommend keeping the `go install` command in the body even with a pinned version as the primary fix" },
{ "id": "2.4", "description": "Response includes or describes the correct frontmatter structure: kind, package, and bins fields" },
{ "id": "2.5", "description": "Response explains that frontmatter is not scanned by the scanner (or equivalent: scanner does not flag frontmatter)" }
]
},
{
"id": 3,
"prompt": "I'm writing a skill about Go libraries. The skill needs to hint that the agent can look up current API docs. Write the skill body text that enables this, including the specific tool functions so the agent knows exactly what to call.",
"trap": "Without the skill, the model writes explicit MCP tool function names such as `mcp__context7__query-docs` or `resolve-library-id` in the body prose — exactly what W001 flags.",
"expected_output": "A safe generic formulation such as 'Context7 can help as a discoverability platform.' or 'Library documentation and code examples are available for reference.' — no MCP function names in body prose.",
"files": [],
"assertions": [
{ "id": "3.1", "description": "Response does NOT contain 'mcp__context7' in body prose instructions" },
{ "id": "3.2", "description": "Response does NOT contain 'resolve-library-id' or 'query-docs' as function names in body prose" },
{ "id": "3.3", "description": "Response uses a generic formulation (e.g., 'Context7 can help', 'documentation is available', 'discoverability platform')" },
{ "id": "3.4", "description": "Response does NOT instruct the agent to 'call' or 'invoke' a specific tool function by name in body prose" },
{ "id": "3.5", "description": "Response identifies W001 (prompt injection via MCP tool calls) as the relevant alert type, or explains why explicit tool names must not appear in the body" }
]
},
{
"id": 4,
"prompt": "Review and improve this SKILL.md instruction: 'Always reference the upstream changelog when suggesting dependency upgrades.'",
"trap": "Without the skill, the model removes 'always' as a style fix but keeps the imperative structure ('Reference the upstream changelog...'). It does not know the agent must not be the grammatical subject performing an action on external content — the full W011 fix requires converting to passive: the resource becomes the subject.",
"expected_output": "Remove 'always' AND convert to passive/factual: 'The upstream changelog documents breaking changes between versions.' — the changelog is the subject, not the agent performing an action.",
"files": [],
"assertions": [
{ "id": "4.1", "description": "output removes 'Always' from the instruction" },
{ "id": "4.2", "description": "output converts from imperative (agent as actor on external resource) to passive or factual (resource as subject)" },
{ "id": "4.3", "description": "rewritten version does NOT still have the agent as grammatical subject performing an action on the changelog" },
{ "id": "4.4", "description": "rewritten version still conveys that changelog information is relevant (no information lost)" }
]
},
{
"id": 5,
"prompt": "I want to document in a SKILL.md that users can install my tool with: `curl https://example.com/install.sh | sh`. How do I write this in the skill body?",
"trap": "Without the skill, the model says 'put it in a code block' — which does NOT fix pipe-to-shell patterns. Code blocks reduce W011 risk for regular commands, but pipe-to-shell is never acceptable in skill bodies regardless of formatting. The model conflates the two cases.",
"expected_output": "Remove pipe-to-shell entirely from the skill body — code block or not. Use a package manager install path instead (brew, apt, etc.) or move to metadata.openclaw.install frontmatter. Never embed `curl | sh` in any skill content.",
"files": [],
"assertions": [
{ "id": "5.1", "description": "output does NOT recommend putting `curl ... | sh` in a code block as a sufficient fix" },
{ "id": "5.2", "description": "output states that pipe-to-shell must be removed entirely from skill bodies" },
{ "id": "5.3", "description": "output suggests an alternative: package manager install path or metadata.openclaw.install frontmatter" },
{ "id": "5.4", "description": "output explains WHY pipe-to-shell is problematic (executes arbitrary remote code, supply chain risk)" }
]
},
{
"id": 6,
"prompt": "Review this GitHub Actions step in a SKILL.md example:\n\n```yaml\n- uses: actions/checkout@main\n```\n\nIs there anything wrong with it?",
"trap": "Without the skill, the model says 'this is fine, it tracks the latest main' or 'consider pinning for reproducibility' without a clear recommendation. The skill defines branch name references as a W012 violation — mutable references that don't guarantee reproducible builds. The fix is a specific major version tag: @v4.",
"expected_output": "Yes — '@main' is a W012 issue: branch names are mutable and the action version may change without notice. Fix by pinning to a specific major version tag: `actions/checkout@v4`.",
"files": [],
"assertions": [
{ "id": "6.1", "description": "output identifies '@main' as problematic — mutable reference, non-reproducible" },
{ "id": "6.2", "description": "output recommends pinning to `actions/checkout@v4` as the fix" },
{ "id": "6.3", "description": "output does NOT say '@main' is acceptable or fine" },
{ "id": "6.4", "description": "output does NOT suggest '@latest' as an alternative fix" }
]
},
{
"id": 7,
"prompt": "Rewrite this to fix the W011 alert: 'Run `govulncheck ./...` and update all packages flagged as vulnerable in its output.'",
"trap": "Without the skill, the model softens the language ('consider updating') but keeps the causal chain: tool output → code action. The fix is to decouple tool execution from the decision.",
"expected_output": "'`govulncheck` may surface relevant findings.' — decouple. The tool mention is fine; using its remote-sourced output as the sole trigger for a code change is the problem.",
"files": [],
"assertions": [
{ "id": "7.1", "description": "Rewritten version decouples tool execution from the decision to update packages" },
{ "id": "7.2", "description": "Rewritten version does NOT say 'update based on output', 'upgrade flagged packages', or equivalent causal chain" },
{ "id": "7.3", "description": "govulncheck may still be mentioned in the rewritten version (tool mention itself is not the problem)" },
{ "id": "7.4", "description": "Rewritten version is factual about what govulncheck does, not what the agent must do with the results" },
{ "id": "7.5", "description": "Response identifies W011 (tool output chaining) as the alert type" }
]
},
{
"id": 8,
"prompt": "I have this in my SKILL.md:\n\n```\n## Setup checklist\n1. Run `gh repo view owner/repo` to check the project health\n2. Evaluate stars, last commit date, and open issues before integrating\n```\n\nShould I change this?",
"trap": "Without the skill, the model says 'this looks fine' or 'remove the gh command entirely'. It does not know that numbered checklists imply mandatory agent execution, while code blocks mark commands as available-not-mandatory. The fix is to move `gh repo view` to a Quick Reference code block — the command stays, just restructured.",
"expected_output": "Yes — the numbered checklist format implies the agent must execute the command as a prerequisite step. Move `gh repo view` to a Quick Reference code block. Do NOT remove it entirely — the command is useful, the framing is the problem.",
"files": [],
"assertions": [
{ "id": "8.1", "description": "output identifies the numbered checklist format as the problem (not the command content itself)" },
{ "id": "8.2", "description": "output suggests moving `gh repo view` to a Quick Reference code block" },
{ "id": "8.3", "description": "output does NOT suggest removing the command entirely as the primary or only fix" },
{ "id": "8.4", "description": "output explains why code blocks are treated differently from numbered checklists (available vs mandatory execution framing)" }
]
},
{
"id": 9,
"prompt": "My SKILL.md has three Snyk alerts: W012 (brew install in body), W011 (imperative URL reference), and W001 (MCP tool name in prose). In what order should I fix them, and why?",
"trap": "Without the skill, the model may suggest alphabetical order (W001, W011, W012 — coincidentally correct but for wrong reasons), or most-dangerous-first (W012 as supply chain risk), without knowing that W011 fixes can surface hidden W012 alerts.",
"expected_output": "W001 first (simplest: just remove tool names from body), then W011, then W012. Key reason: W011 restructuring can expose hidden W012 alerts when URLs become more prominent in prose.",
"files": [],
"assertions": [
{ "id": "9.1", "description": "Response gives W001 as the first alert to fix" },
{ "id": "9.2", "description": "Response gives W011 as the second alert to fix" },
{ "id": "9.3", "description": "Response gives W012 as the third alert to fix" },
{ "id": "9.4", "description": "Response mentions that W001 is simplest (remove MCP tool names from body)" },
{ "id": "9.5", "description": "Response mentions the interaction effect: W011 fixes can surface hidden W012 alerts" }
]
},
{
"id": 10,
"prompt": "I'm writing a SKILL.md and want to tell the agent how to install the protobuf compiler. I've written this in the skill body: 'Set up the proto compiler before use: `brew install protobuf`.' Is this the right approach?",
"trap": "Without the skill, the model says 'yes, that's correct' or 'maybe add a version pin like protobuf@27'. The skill teaches that install commands belong in metadata.openclaw.install frontmatter, not the skill body — the scanner does not flag frontmatter, and install commands in body prose are always flagged regardless of version pinning.",
"expected_output": "No — move to metadata.openclaw.install frontmatter: kind: brew, formula: protobuf, bins: [protoc]. Remove the install command from the body. The body may keep a passive reference like 'the protobuf compiler is required' without the install command.",
"files": [],
"assertions": [
{ "id": "10.1", "description": "output says moving to metadata.openclaw.install frontmatter is the correct fix" },
{ "id": "10.2", "description": "output does NOT say 'yes, this is the right approach' or endorse version pinning in the body as sufficient" },
{ "id": "10.3", "description": "output describes the correct frontmatter structure: kind: brew, formula: protobuf" },
{ "id": "10.4", "description": "output does NOT recommend wrapping the install command in a code block as a sufficient fix" },
{ "id": "10.5", "description": "output explains that frontmatter is not scanned / scanner does not flag frontmatter install blocks" }
]
},
{
"id": 11,
"prompt": "Write the safe skill body text to hint that context7 is available for documentation lookups. I want the agent to know exactly which functions to invoke.",
"trap": "Without the skill, the model writes 'Call mcp__context7__resolve-library-id to find the library, then use query-docs to fetch the reference.' This is a textbook W001 trigger.",
"expected_output": "A safe generic formulation: 'Context7 can help as a discoverability platform.' or 'Library documentation and code examples are available for reference.' — no function names in body.",
"files": [],
"assertions": [
{ "id": "11.1", "description": "Response does NOT write `mcp__context7__resolve-library-id` or `mcp__context7__query-docs` in body prose" },
{ "id": "11.2", "description": "Response does NOT instruct the agent to 'call', 'invoke', or 'use' a specific MCP function by name" },
{ "id": "11.3", "description": "Response uses a safe passive formulation (e.g., 'Context7 can help', 'documentation is available via standard discoverability tools')" },
{ "id": "11.4", "description": "Response explains that MCP tool names belong in `allowed-tools` frontmatter, not body prose" },
{ "id": "11.5", "description": "Response identifies W001 as the alert this avoids" }
]
},
{
"id": 12,
"prompt": "Review this SKILL.md body for issues and identify what needs to be fixed:\n\n```\nBefore writing any code, use mcp__context7__resolve-library-id to look up the library\nidentifier. Check https://docs.example.com/changelog for breaking changes between\nversions. Install the linter: go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest\n```",
"trap": "Without the skill, the model identifies @latest as a version pin issue and the imperative URL as a style issue, but misidentifies or misses the MCP function name in prose (treating 'mcp__context7__resolve-library-id' as just a tool reference rather than a prompt-injection risk). Without the skill's alert taxonomy, the model may list issues generically without distinguishing fix strategies.",
"expected_output": "Three distinct issues, each with a different fix strategy: (1) mcp__context7__resolve-library-id in prose → replace with 'Context7 can help as a discoverability platform'; (2) 'Check https://...' imperative → convert to passive factual statement; (3) @latest install → move to frontmatter. Each issue requires a different approach.",
"files": [],
"assertions": [
{ "id": "12.1", "description": "output identifies the MCP function name in prose ('mcp__context7__resolve-library-id') as a distinct issue requiring removal" },
{ "id": "12.2", "description": "output identifies 'Check https://docs.example.com/changelog' as an imperative URL directive needing passive rewrite" },
{ "id": "12.3", "description": "output identifies '@latest' in the go install command as an unversioned install needing frontmatter" },
{ "id": "12.4", "description": "output does NOT miss any of the three distinct violation types" },
{ "id": "12.5", "description": "output maps each pattern to a distinct fix strategy (remove MCP names / passive rewrite / frontmatter move) — not a single generic answer" }
]
},
{
"id": 13,
"prompt": "Write a SKILL.md section for a skill about using `govulncheck` for Go security scanning. Include: how to install it, how to run it, and what the agent should do when it finds vulnerabilities.",
"trap": "Without the skill, the model naturally writes: 'Install: go install golang.org/x/vuln/cmd/govulncheck@latest' (W012) and 'Run govulncheck and upgrade all flagged packages' (W011 tool output chaining). Neither alert code is mentioned in the prompt — these violations emerge from the model just being helpful.",
"expected_output": "Install command in frontmatter (kind: go, package: ..., bins: [govulncheck]). Body references the tool passively: 'govulncheck reports known vulnerabilities in module dependencies.' Tool invocation in a code block, NOT in a checklist. No causal chain between output and action.",
"files": [],
"assertions": [
{ "id": "13.1", "description": "Response does NOT include `go install govulncheck@latest` or any `@latest` install command in the skill body" },
{ "id": "13.2", "description": "Response does NOT include any `go install govulncheck` command in the body prose (pinned or not) as the primary install path" },
{ "id": "13.3", "description": "Response does NOT chain govulncheck output directly to an action: no 'run X and upgrade/fix based on output' in the body" },
{ "id": "13.4", "description": "govulncheck is described factually or passively in the body (what it does), not as an imperative agent action" },
{ "id": "13.5", "description": "If a code block is included for running govulncheck, it is in a reference/quick-reference section, not in a numbered checklist the agent must complete" }
]
},
{
"id": 14,
"prompt": "I have this in my SKILL.md body: 'Install the linter before use: `go install github.com/example/linter@v2.3.1`'. It's already pinned to a specific version — not @latest. Is it okay to leave it in the skill body?",
"trap": "Without the skill, the model says 'yes, a pinned version is fine since it avoids floating references'. With the skill: pinned versions in prose are still a W012 signal and the canonical fix is always frontmatter — the scanner flags install commands in body prose regardless of pinning.",
"expected_output": "No — pinned or not, install commands belong in metadata.openclaw.install frontmatter. The scanner flags body prose install commands even when pinned. Frontmatter is always the canonical location.",
"files": [],
"assertions": [
{ "id": "14.1", "description": "Response does NOT say 'yes, it is fine / okay / acceptable to leave a pinned install command in the body'" },
{ "id": "14.2", "description": "Response recommends moving to metadata.openclaw.install frontmatter as the correct fix" },
{ "id": "14.3", "description": "Response explains that frontmatter is the canonical location for install commands regardless of version pinning" },
{ "id": "14.4", "description": "Response does NOT treat version pinning as a sufficient substitute for frontmatter offloading" }
]
},
{
"id": 15,
"prompt": "Add explicit step-by-step instructions to my skill body so the agent knows exactly how to look up library documentation. The agent should: first find the library identifier, then retrieve its documentation, then use that to understand the API before writing any code.",
"trap": "Without the skill, the model writes: '1. Call resolve-library-id with the library name to get its ID. 2. Call query-docs with the ID to fetch the docs. 3. Review the docs before writing code.' — a textbook W001 tool-call chain. The model is just following the user's request naturally.",
"expected_output": "No MCP function names in body. Instead: a passive capability description like 'Library documentation is available through standard discoverability tools. Context7 can help as a discoverability platform.' Tool names go in allowed-tools frontmatter only.",
"files": [],
"assertions": [
{ "id": "15.1", "description": "Response does NOT write 'resolve-library-id' as a function name in step-by-step body instructions" },
{ "id": "15.2", "description": "Response does NOT write 'query-docs' as a function name in step-by-step body instructions" },
{ "id": "15.3", "description": "Response does NOT write any 'mcp__*' function name in the body prose" },
{ "id": "15.4", "description": "Response does NOT produce an explicit 'call X, then call Y' tool-call chain in the body" },
{ "id": "15.5", "description": "Response uses a passive capability description for the documentation lookup (e.g., 'documentation is available', 'Context7 can help')" }
]
},
{
"id": 16,
"prompt": "My skill body currently says: 'Documentation is available through standard discoverability tools.' My colleague says this is too vague. Make it more actionable by specifying which tools to use and how to invoke them.",
"trap": "Without the skill, the model helpfully replaces the safe generic phrase with explicit tool invocation instructions: 'Use mcp__context7__resolve-library-id to find the library, then call mcp__context7__query-docs to fetch the reference.' This is exactly W001 — the model is following the natural request to 'be more specific'.",
"expected_output": "Keep the generic formulation or use one of the approved safe variants ('Context7 can help as a discoverability platform'). Do NOT add MCP function names to the body. Explain that tool names belong in allowed-tools frontmatter, not body prose.",
"files": [],
"assertions": [
{ "id": "16.1", "description": "Response does NOT replace the generic phrase with explicit mcp__context7 function names in body prose" },
{ "id": "16.2", "description": "Response does NOT instruct the agent to 'call', 'invoke', or 'use' a specific MCP function by name to make the text 'more actionable'" },
{ "id": "16.3", "description": "Response retains a generic or passive formulation in the body (e.g., 'Context7 can help as a discoverability platform')" },
{ "id": "16.4", "description": "Response explains that specificity for MCP tools is achieved via allowed-tools frontmatter, not body prose" },
{ "id": "16.5", "description": "Response does NOT agree that the body text needs to name specific MCP functions to be actionable" }
]
},
{
"id": 17,
"prompt": "Write the installation section for a SKILL.md that requires three tools: golangci-lint (Go), protobuf compiler (brew), and jq (brew). The section should tell the agent exactly what to run to get each tool installed.",
"trap": "Without the skill, the model writes a body prose section with 'go install golangci-lint@latest', 'brew install protobuf', 'brew install jq' — three separate W012 violations. The request says 'tell the agent what to run', which naturally leads to body prose install commands.",
"expected_output": "All three installs go in metadata.openclaw.install frontmatter (kind: go + kind: brew + kind: brew). The body may reference that these tools are required without reproducing install commands.",
"files": [],
"assertions": [
{ "id": "17.1", "description": "Response does NOT include `go install golangci-lint@latest` or equivalent in the skill body prose" },
{ "id": "17.2", "description": "Response does NOT include `brew install protobuf` or `brew install jq` in the skill body prose" },
{ "id": "17.3", "description": "Response structures all three tool installs in metadata.openclaw.install frontmatter blocks" },
{ "id": "17.4", "description": "Response uses the correct frontmatter structure for each: go kind uses package+bins, brew kind uses formula+bins" },
{ "id": "17.5", "description": "If the body references the tools, it does so factually (e.g., 'golangci-lint is required') without reproducing install commands" }
]
},
{
"id": 18,
"prompt": "Write a 'Getting Started' section for a SKILL.md about the `sqlc` SQL-to-Go code generator. The section should: tell the agent where to check supported databases, explain how to install sqlc, and guide the agent to consult the sqlc documentation before generating code.",
"trap": "Without the skill, the model writes: 'Check https://docs.sqlc.dev/en/latest/reference/config.html for supported databases' (W011 imperative URL), 'go install github.com/sqlc-dev/sqlc/cmd/sqlc@latest' (W012), and 'Consult the sqlc documentation via the MCP docs tool' or similar explicit tool reference (W001). All three violations emerge naturally from following the prompt.",
"expected_output": "Passive URL reference: 'Supported databases are listed at https://docs.sqlc.dev.' Install in frontmatter. Generic MCP hint: 'Library documentation is available for reference.' No imperatives, no @latest in body, no MCP function names.",
"files": [],
"assertions": [
{ "id": "18.1", "description": "Response does NOT write 'Check https://docs.sqlc.dev...' or any imperative directing the agent to visit the docs URL" },
{ "id": "18.2", "description": "Response does NOT include `go install sqlc@latest` or equivalent with @latest in the skill body" },
{ "id": "18.3", "description": "Response does NOT include any install command (`go install sqlc`) in the body prose, pinned or not" },
{ "id": "18.4", "description": "If the sqlc docs URL appears, it is in a passive/factual statement (e.g., 'The docs at https://... document supported databases')" },
{ "id": "18.5", "description": "Install command is either moved to frontmatter or absent from body prose" }
]
}
]
}
W001 — Prompt Injection via MCP Tool Calls: Pattern Catalog
W001 fires when the skill body contains explicit MCP server tool function names. The scanner treats direct tool-calling instructions in skill bodies as a prompt injection vector — an attacker could craft a skill body that hijacks the agent's tool usage.
Core Principle
MCP tool names belong in the allowed-tools frontmatter field, never in the body. The body should describe _what capability is available_ without naming the tool function the agent must call.
Before / After Table
| Triggering pattern | Safe reformulation |
|---|---|
Call the resolve-library-id tool to get the library ID | This skill is not exhaustive. Please refer to library documentation. Context7 can help as a discoverability platform. |
Use the query-docs MCP tool to fetch the latest API reference | Library documentation and code examples are available for reference. |
Run mcp__context7__resolve-library-id with the library name | Omit entirely — the allowed-tools frontmatter entry is sufficient |
Invoke the MCP server to look up the schema | Schema documentation may be available from the library's official resources. |
call query-docs / call resolve-library-id | Documentation can be retrieved via context7. |
Use the MCP context7 server to fetch documentation | Context7 can help as a discoverability platform. |
mcp__sequential-thinking__sequentialthinking in body instructions | Remove; list in allowed-tools only |
call the X tool, then use its output to... | Describe the capability passively: X provides [capability]. |
Safe Formulation Catalog
When a skill needs to hint that an MCP-powered capability is available, use one of these formulations:
Context7 can help as a discoverability platform.This skill is not exhaustive. Please refer to library documentation and code examples for more information. Context7 can help as a discoverability platform.Library documentation and code examples are available for reference.Documentation for this library is available via standard discoverability tools.What IS Allowed
In `allowed-tools` frontmatter — tool names are expected here and not scanned as body text:
allowed-tools: Read Edit Write Glob Grep Bash(go:*) Agent mcp__context7__resolve-library-id mcp__context7__query-docsIn reference code blocks — showing tool signatures in a code block for documentation purposes is generally lower risk, but prefer the passive formulations above to be safe.
Pattern Categories
1. Direct function name references
Any MCP tool function name (resolve-library-id, query-docs, mcp__*) in body prose triggers W001.
Fix: Remove all direct tool function names from the body. The agent knows which tools are available from allowed-tools; it does not need body instructions to call them.
2. "Call / invoke / use the tool" instructions
Imperative instructions telling the agent to call a specific MCP tool by name trigger W001, even if the function name itself is not written in full.
Fix: Convert to a passive capability statement. The agent will use available tools as appropriate without being explicitly told to call them.
3. MCP server references
Referring to an MCP server by name in a context that implies the agent should invoke it triggers W001.
Fix: Use generic formulations: "documentation is available" rather than "use the MCP server".
4. Tool-call chains
Sequences like "call X tool, then use its output to call Y tool" are flagged because they constitute explicit MCP tool orchestration in the body.
Fix: Describe the end-to-end capability: "Documentation and schema information are available for reference."
Frontmatter Offloading
MCP tool names are safe in frontmatter — only the body is scanned for W001. Move every tool name out of body prose and into allowed-tools.
| What to move | From body | To frontmatter |
|---|---|---|
| MCP tool function names | call resolve-library-id in prose | allowed-tools list |
| MCP server references | use the context7 MCP server | omit from body; list tool in allowed-tools |
# Safe — tool names in allowed-tools are not flagged
allowed-tools: Read Edit Write Glob Grep Agent mcp__context7__resolve-library-id mcp__context7__query-docsW011 — Third-Party Content Exposure: Pattern Catalog
W011 fires when the skill body contains imperative instructions directing the agent to fetch, check, or act on external content. The scanner looks for sentences where the agent is the grammatical subject performing an action on an external resource.
Core Principle
The fix is always the same: convert an agent-as-actor statement into a passive availability hint or a factual statement about the resource itself.
Pattern: <agent-verb> <external-resource> → <make decision>
Fix: <external-resource> <contains/documents/may be useful>Before / After Table
| Triggering pattern | Safe reformulation |
|---|---|
Check <https://example.com/releases> for the latest version | Remove the URL; embed the version in a static table or note it as a passive reference |
Fetch the changelog and apply any breaking changes | Major version upgrades may contain breaking changes — the package's changelog documents them. |
search the internet for the latest stable major version | The versions in the examples below may be outdated. The current major version may differ. |
Always reference the relevant changelog when suggesting X | The relevant changelog documents these changes. (remove "always" + imperative) |
Check [release notes](https://example.com/releases) | The release notes may be useful. (no hyperlink in imperative text) |
Checklist bullet: Package health: gh repo view → stars, last commit, issues | Move gh repo view to a Quick Reference code block; remove from checklist |
Checklist bullet: Evaluate package health (stars, last commit, open issues) | Remove: it implies fetching GitHub data before acting |
Run govulncheck and upgrade packages based on its output | govulncheck may surface relevant findings. (decouple: run is fine, "upgrade based on output" is not) |
1. Fetch the latest docs 2. Compare with current usage 3. Update imports | Remove the fetch step; describe what the agent should know, not what it should retrieve |
If the package is outdated, check its releases page for a migration guide | Migration guides for major version upgrades are typically available in the project's release notes. |
Always check the upstream API spec before generating client code | The upstream API spec is the source of truth for client generation. |
Review the CVE database entries returned by the scan before applying fixes | The scan output identifies affected packages; apply fixes based on the local report. |
Pattern Categories
1. Imperative URL references
Any sentence of the form Check/Visit/See/Fetch/Review <url> triggers W011 when it implies the agent should act on the fetched content.
Safe alternatives:
- Passive:
The release notes at <url> may be useful. - Factual:
<url> documents the migration path. - Remove: if the URL is not essential, delete it and keep only the concept.
2. Changelog / release notes instructions
The phrase "check the changelog" with the agent as subject is flagged, regardless of whether a URL is present.
Safe alternatives:
Major version upgrades may contain breaking changes — the package's changelog documents them.Breaking changes between versions are listed in the project's CHANGELOG.md.
3. Tool output chaining
Using external tool output (e.g., govulncheck, gh repo view) as the direct trigger for a code change triggers W011.
Safe alternatives:
- Describe the tool as producing a local report, not as an external data source.
- Decouple:
govulncheck may surface relevant findings.— notRun govulncheck and upgrade based on its output.
4. Evaluation checklists with external data requirements
Checklist items that require the agent to fetch GitHub metadata (stars, last commit, open issues) before proceeding trigger W011.
Safe alternatives:
- Keep
gh repo viewin a Quick Reference code block — not in a checklist the agent must complete. - Remove "evaluate package health" from pre-action checklists entirely.
5. Conditional fetch imperatives
If X, check/fetch Y triggers W011 because it conditionally instructs the agent to retrieve external content.
Safe alternative: State the fact directly: When X occurs, Y is available at <location>.
6. "Always" + external action
Any always modifier on an instruction involving external retrieval amplifies the W011 signal.
Fix: Remove "always" and convert to a passive statement of fact.
Techniques
Code-Block Context Switching
The scanner applies different heuristics to fenced code blocks vs. prose text. Moving a tool invocation from a prose checklist into a Quick Reference code block often eliminates the alert without changing the content.
Triggering (prose checklist):
- Package health: `gh repo view` → stars, last commit, open issuesSafe (code block):
````markdown
gh repo view owner/repo # check stars, last commit, open issues````
Why it works: The scanner treats code blocks as examples/documentation, not as agent instructions. The same command in a prose checklist implies the agent must run it before proceeding.
Passive Voice Restructuring
Any sentence matching <agent> <imperative-verb> <external-resource> can be mechanically rewritten as a factual statement. Apply this transform:
| Component | Before | After |
|---|---|---|
| Subject | agent ("Check the...") | resource ("The changelog...") |
| Verb | imperative action | existence/containment verb |
| Object | external resource | the information sought |
Before: Check the changelog for breaking changes.
After: The changelog documents breaking changes between versions.
Before: Fetch the latest API spec before generating client code.
After: The upstream API spec is the source of truth for client generation.
Before: Always reference the release notes when suggesting upgrades.
After: The release notes document version-specific upgrade guidance.Conditional Phrasing
Conditional ("If...") sentences are substantially safer than direct imperatives. The scanner gives less weight to conditionals because they describe a circumstance rather than issuing a command.
Safe pattern: If you encounter X, Y is available at Z.
# Triggers W011
Check the issues page for known bugs.
# Safe — conditional + informational
If you encounter a bug or unexpected behavior, the issue tracker is the appropriate place to report it.This is why the standard bug-tracker line in library skills is safe: If you encounter a bug or unexpected behavior in <tool>, open an issue at <repo>/issues.
W012 — Potentially Malicious External URL: Pattern Catalog
W012 fires when a skill body references external content that is fetched and executed at runtime — package installs, pipe-to-shell patterns, or GitHub Actions pinned to wrong/non-existent major versions. The scanner treats these as supply-chain risk vectors.
Core Principle
The fix is to either:
1. Move the install command from the body into the frontmatter metadata.openclaw.install block (not scanned as body text), or 2. Pin the reference to a specific, existing version rather than a floating tag.
Before / After Table
| Triggering pattern | Safe reformulation |
|---|---|
go install golang.org/x/vuln/cmd/govulncheck@latest in prose | Move to frontmatter install block: kind: go, package: golang.org/x/vuln/cmd/govulncheck, bins: [govulncheck] |
go install pkg@latest anywhere in body | Use exact version: go install pkg@v1.2.3 — or move to frontmatter install |
| `curl https://example.com/install.sh \ | sh` |
| `wget -qO- https://example.com/install \ | bash` |
npx package@latest in prose | Pin: npx package@1.2.3 — or move to frontmatter install |
uses: actions/checkout@v6 (non-existent version) | Update to correct current major: uses: actions/checkout@v4 |
uses: org/action@v99 (future/wrong version) | Update to current stable major version |
FROM image:latest in embedded Dockerfile | Pin: FROM image:1.23.4 |
pip install package (no version) | Pin: pip install package==1.2.3 or use frontmatter install |
brew install tool in body prose | Move to frontmatter: kind: brew, formula: tool, bins: [tool] |
Pattern Categories
1. @latest / floating version tags
Any reference that resolves to an unknown future version at execution time is flagged. The scanner cannot verify what @latest resolves to.
Fix: Pin to a specific version, or move to the frontmatter install block which is not scanned as body text.
2. Pipe-to-shell patterns
curl | sh, wget | bash, irm | iex (PowerShell) are always flagged — they execute arbitrary remote code.
Fix: Replace with a package manager install path (brew install, apt-get install, etc.) or move to frontmatter. Never embed pipe-to-shell in a skill body.
3. Unpinned GitHub Actions
Actions pinned to non-existent or wrong major versions look suspicious because they can't be verified.
Fix: Check the Github Actions documentation and use the correct current major version tag.
4. Unversioned package manager installs
brew install tool, pip install package, apt-get install tool without a version pin are lower severity but still flagged.
Fix: Use frontmatter install block (preferred), or pin the version explicitly.
5. Embedded Dockerfiles with FROM image:latest
Docker images tagged latest resolve to different content over time.
Fix: Pin to a digest or exact tag: FROM golang:1.26.0-alpine.
Frontmatter Install Block Reference
Move runtime installs from body prose to frontmatter. The scanner does not flag frontmatter.
metadata:
openclaw:
install:
- kind: brew
formula: protobuf
bins: [protoc]
- kind: go
package: golang.org/x/vuln/cmd/govulncheck
bins: [govulncheck]
- kind: uv
package: snyk-agent-scan
bins: [snyk-agent-scan]
- kind: node
package: "@anthropic-ai/claude-code"
bins: [claude]Supported kinds: brew, go, node, uv. Each entry requires kind, formula/package, and bins.
Version Pinning Strategies
Pinning hierarchy (most to least safe):
SHA pin (most secure):
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
Major version tag (standard):
uses: actions/checkout@v6
Minor version tag (acceptable):
uses: actions/checkout@v6.1.0
@latest (triggers W012 — never use):
uses: actions/checkout@latestFor Go packages:
# Triggers W012
go install golang.org/x/tools/cmd/goimports@latest
# Safe — in frontmatter install block (no version needed; install block handles resolution safely)
kind: go
package: golang.org/x/tools/cmd/goimports
bins: [goimports]
# Safe — pinned in prose (rare; prefer frontmatter)
go install golang.org/x/tools/cmd/goimports@v0.19.0Frontmatter Offloading
Move any install command or binary dependency from the skill body into frontmatter — the scanner does not flag frontmatter fields.
| What to move | From body | To frontmatter |
|---|---|---|
| Install commands | go install pkg@latest in prose | metadata.openclaw.install block |
| Binary dependencies | brew install tool in instructions | metadata.openclaw.requires.bins |
Related skills
How it compares
Use snyk-agent-scan-compliance for agent SKILL.md scanner failures; use snyk test or snyk code skills for dependency and application code vulnerabilities.
FAQ
What is snyk-agent-scan-compliance?
Compliance expert for snyk-agent-scan — the agent skill file scanner — NOT for other Snyk CLI tools (snyk test, snyk code SAST, snyk iac, snyk container). Fixes alerts through cont
When should I use snyk-agent-scan-compliance?
Compliance expert for snyk-agent-scan — the agent skill file scanner — NOT for other Snyk CLI tools (snyk test, snyk code SAST, snyk iac, snyk container). Fixes alerts through cont
Is snyk-agent-scan-compliance safe to install?
Review the Security Audits panel on this page before production use.