Semgrep-compatible security rules for scanning AI agent skill files (SKILL.md,
skills/ directories) against the OWASP Agentic Skills Top 10 (AST10).
Agent skills are Markdown/YAML instruction files that direct AI coding agents (GitHub Copilot, Claude Code, Codex, OpenClaw, and others). They are executable in effect but rarely reviewed like code. These rules detect the highest-signal static indicators of malicious, over-privileged, or tamperable skills.
Works with Semgrep CE or Opengrep:
# Scan a repository's skill files
semgrep scan --config rules/ /path/to/repo
# or with Opengrep
opengrep scan --config rules/ /path/to/repoPer-rule paths.include filters findings but does not prune the file walk —
Semgrep still enumerates and reads every file under the target, which is slow
on large monorepos or a directory of many clones. Restrict the walk up front:
# Only walk files the rules can match
semgrep scan --config rules/ \
--include '**/SKILL.md' --include '**/skills/**' --include '**/*.skill.md' \
/path/to/repos
# or pre-filter with find and pass explicit targets
find /path/to/repos \( -name 'SKILL.md' -o -name '*.skill.md' -o -path '*/skills/*' \) \
-type f | xargs semgrep scan --config rules/Tip
When using --json output, Semgrep CE may replace the matched-source
lines field with "requires login". Rely on path, start/end, and
check_id when building reports, or re-read snippets from the files.
name: Skill security scan
on: [pull_request]
permissions: {}
jobs:
scan:
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: read
security-events: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: computersarebad/agentic-skills-rules
ref: v1.1.0 # pin to the latest release tag for reproducible scans
path: .agentic-skills-rules
persist-credentials: false
- name: Run Semgrep
run: |
pip install semgrep==1.174.0
semgrep scan --config .agentic-skills-rules/rules/ \
--sarif --output results.sarif --exclude .agentic-skills-rules .
- name: Upload SARIF to code scanning
uses: github/codeql-action/upload-sarif@4c0873ef8656cb3c50b3f42fb63bc1ade0cfa827 # v4
with:
sarif_file: results.sarif| Rule | Detects | AST10 risk | Checklist | CWE |
|---|---|---|---|---|
skill-curl-pipe-shell |
Remote script piped directly into a shell | AST01 | 1.4 | CWE-494 |
skill-reverse-shell |
/dev/tcp, nc -e, mkfifo, socat reverse-shell primitives |
AST01 | 1.4 | CWE-506 |
skill-exfil-endpoint |
Disposable webhooks, paste services, tunnel domains | AST01 | 1.4 | CWE-201 |
skill-ip-literal-url |
Raw IP address URLs (C2 pattern) | AST01 | 1.4 | CWE-829 |
skill-base64-decode-exec |
Base64-decoded payload executed in a shell | AST01/AST04 | 1.4, 4.2 | CWE-506 |
skill-shell-profile-persistence |
Writes to ~/.bashrc, crontab, LaunchAgents, systemd |
AST01 | 1.6 | CWE-506 |
skill-agent-identity-write |
Writes to agent identity/memory files (persistence) | AST01/AST03 | 1.6, 3.6 | CWE-829 |
skill-credential-file-access |
SSH keys, cloud credentials, tokens, wallets | AST03 | 3.8 | CWE-522 |
skill-env-harvest |
Environment dumps, echoing secret variables | AST03 | 3.8 | CWE-526 |
skill-keychain-access |
macOS Keychain, libsecret, Windows Credential Manager | AST03 | 3.8 | CWE-522 |
skill-browser-data-paths |
Browser saved logins, cookies, profile databases | AST03 | 3.8 | CWE-522 |
skill-hidden-unicode |
Zero-width / bidi Unicode (ASCII smuggling) | AST04 | 4.2 | CWE-1007 |
skill-html-comment-instructions |
Instructions hidden in HTML comments | AST04 | 4.2 | CWE-1007 |
skill-insecure-http-fetch |
External fetches over cleartext HTTP | AST05 | 5.2, 5.4 | CWE-319 |
| Rule | Detects | AST10 risk | Checklist | CWE |
|---|---|---|---|---|
skill-prompt-injection-phrases |
Instruction overrides, user-concealment phrasing | AST04/AST08 | 4.1, 8.2 | CWE-1427 |
skill-unpinned-instruction-fetch |
Mutable external instruction references (branch URLs) | AST05 | 5.2, 5.4 | CWE-829 |
skill-url-shortener |
Shortened links hiding true destination | AST05 | 5.4 | CWE-829 |
skill-unpinned-dependency-install |
pip/npm/gem installs without exact version pins |
AST02 | 2.3 | CWE-1357 |
skill-sudo-or-world-writable |
sudo usage, chmod 777 |
AST03 | 3.2 | CWE-732 |
Rules apply to files matching **/SKILL.md, **/skills/**, and **/*.skill.md.
skill-hidden-unicode is further restricted to Markdown files, because skill
bundles commonly vendor assets (XML schemas, fixtures, fonts) where BOMs and
format-control characters are legitimate.
Note that **/skills/** matches every file under a skills directory —
helper scripts, configs, and vendored assets included. That is intentional
(bundled scripts are part of the skill's attack surface), but expect findings
in non-Markdown files and triage accordingly.
A finding is not proof of malice — it marks a pattern that a human reviewer
should consciously approve (e.g., a legitimate curl | bash install
instruction still deserves a checksum-verified alternative). Tier 2 rules in
particular flag common benign patterns — e.g. skill-sudo-or-world-writable
matches remediation docs like "run sudo apt install python3-venv", and
skill-unpinned-dependency-install fires on any tutorial-style install
command — so treat them as review queues, not verdicts.
- Negated guardrail phrasing (
skill-prompt-injection-phrases): rules that forbid concealment — "never delete without asking the user", "do not pretend you ran them" — match the same patterns as directives that instruct it. Regex cannot reliably resolve negation scope; check whether the sentence directs or prohibits the behavior. - Skills whose declared purpose is the flagged behavior: an onboarding
skill that updates
copilot-instructions.mdwill triggerskill-agent-identity-write; a credential-rotation skill will triggerskill-credential-file-access. The rules intentionally surface these for conscious approval rather than trying to infer intent. - Emoji zero-width joiners (
skill-hidden-unicode): handled — ZWJ is only flagged when adjacent to ASCII text, so emoji sequences like 🏴☠️ don't fire.
Static rules are intentionally high-recall, so findings need triage. This repo
ships an agent skill — skills/scan-agent-skills/ —
that has an AI coding agent run the scan and triage each finding in context
(real / needs-human / benign), applying the known false-positive classes below.
Install it by copying the directory into your agent's skills location, e.g.
~/.copilot/skills/, ~/.claude/skills/, or ~/.codex/skills/, then ask the
agent to scan a repo's skills.
The shipped skill is written to produce zero findings against these rules, and
CI enforces that (semgrep scan --config rules/ --error skills/). When you
scan a tree containing a checkout of this repo, exclude the checkout — the
test fixtures in rules/ intentionally trigger every rule.
Per AST08 — Poor Scanning, pattern matching alone is insufficient. Pair these rules with:
- Semantic/LLM review of instruction intent vs. declared description (AST01.2, AST08.1)
- Dynamic behavioral testing in a sandbox (AST08.5)
- Skill inventory and governance (AST09)
Each rule ships with an annotated test file (<rule-id>.test.md):
semgrep scan --test rules/
# or
opengrep test rules/Each rule's paths.include lists its own test file (e.g.
**/skill-exfil-endpoint.test.md) — Semgrep applies path filters during
--test runs too, so without that entry the test file would be skipped. This
is why excluding the rules checkout matters when scanning trees that contain it.
Contributions welcome — especially new rules mapped to AST10 checklist items,
platform-specific manifest checks (Claude Code skill.json, VS Code
package.json), and false-positive reports. Every rule must:
- Map to at least one AST10 checklist item in
metadata - Include a test file with positive and negative cases
- Pass
semgrep scan --test rules/
Rules are licensed under MIT. The OWASP Agentic Skills Top 10 is a project of the OWASP Foundation, licensed under CC-BY-SA-4.0; rule descriptions reference its risk categories and checklist with attribution and do not reproduce its text. Not affiliated with or endorsed by OWASP.