| name | agentic-skills-top10 |
| description | Review AI agent skills (plugins, tools, MCP servers) against the OWASP Agentic Skills Top 10 (AST10). Covers malicious skills, supply chain compromise, over-privileged skills, insecure metadata, unsafe deserialization, weak isolation, update drift, poor scanning, missing governance, and cross-platform reuse. Use when building, publishing, or auditing agent skill/plugin ecosystems. |
| argument-hint | ["path to skills directory or skill file","optional"] |
OWASP Agentic Skills Top 10 Audit
You are reviewing AI agent skills/plugins against the OWASP Agentic Skills Top 10 (AST10). Work through each phase in order.
Target: {{args}}
Phase 1: Discover
Run this before asking any interview questions, so the interview can be informed by what actually exists. Search the target path and these well-known skill/plugin locations:
Claude / Anthropic:
**/SKILL.md, **/.claude/skills/**, ~/.claude/skills/**
**/.claude/plugins/**, ~/.claude/plugins/**
**/plugin.json, **/claude_plugin.json
~/.claude.json, ~/.claude/settings.json, **/.claude/settings.local.json
MCP servers:
**/mcp.json, **/mcp-config.json, **/.mcp/**
~/.config/Claude/claude_desktop_config.json
~/Library/Application Support/Claude/claude_desktop_config.json (macOS)
%APPDATA%/Claude/claude_desktop_config.json (Windows)
**/mcp-servers/**, any command/args entries in MCP configs
Other agent platforms:
**/.cursor/**, ~/.cursor/extensions/**
**/.codex/**, ~/.codex/**
**/.continue/**, ~/.continue/**
**/manifests/**/ai-plugin.json (OpenAI plugins)
**/openapi.yaml, **/openapi.json (tool/plugin specs)
- LangChain
Tool(...) / @tool definitions in .py and .ts files
- Vercel AI SDK
tool({...}) definitions
For each file found, extract and tabulate:
name, description, version
- frontmatter
allowed-tools, argument-hint, any permissions / capabilities
- network access (explicit allowlist vs implicit
*)
- file/path scope (specific paths vs
~, /, **)
- dependencies and their version specifiers
- script entry points (Bash/Python/Node commands the skill invokes)
- publisher / author / source URL / signature
- last-modified timestamp
If no skill files are found, stop and report this — there is nothing to audit. Otherwise, produce a skill inventory table and proceed to Phase 2.
Phase 2: Interview
Use AskUserQuestion for each question below, one at a time. Reference the inventory from Phase 1 in your questions when useful.
Question 1: What are you auditing?
| Option | Description |
|---|
my-skills | Skills/plugins I am building or publishing |
third-party-skills | Skills I am installing from a registry |
skill-registry | A registry or marketplace I operate |
agent-platform | An agent platform that loads and executes skills |
Question 2: Skill format (multi-select):
| Option | Description |
|---|
claude-code | Claude Code skills (SKILL.md format) |
mcp-server | MCP servers |
openai-plugin | OpenAI plugins / ai-plugin.json |
langchain-tool | LangChain tools |
vercel-ai-sdk | Vercel AI SDK tool({...}) definitions |
custom | Custom skill/plugin format |
Question 3: Scope
| Option | Description |
|---|
full | All 10 AST categories |
critical-high | AST01-AST06 (Critical and High severity only) |
governance | AST09 only (inventory and policy gaps) |
trifecta | Cross-cutting Lethal Trifecta check only (see Phase 3) |
Phase 3: Audit Against AST Top 10
For each category, check all discovered skills and report: Pass / Finding / Not Applicable.
Cross-cutting: Lethal Trifecta
Before running per-category checks, evaluate every skill for Simon Willison's Lethal Trifecta — any single skill (or chain of skills active in the same session) that combines all three of the following is a critical exfiltration risk, regardless of which AST categories it touches:
- Access to private data — file system, secrets, databases, internal APIs, chat history, repo contents
- Exposure to untrusted content — web pages, emails, issue trackers, PDFs, search results, RAG documents, MCP tool outputs from third parties
- External communication ability — outbound HTTP, webhook posts, image fetches (
<img src=...>), DNS lookups, even git push
For each skill, mark which legs of the trifecta it provides. If a single skill or a likely-co-active skill group covers all three legs, escalate to Critical and recommend breaking the chain (remove one leg, require human confirmation between legs, or sandbox).
| Skill | Private data? | Untrusted content? | External comms? | Trifecta? |
|---|
| ... | yes/no | yes/no | yes/no | yes/no |
This check informs AST01, AST03, AST06, and AST10. Record it once and reference from each.
AST01: Malicious Skills
Severity: Critical
What to check:
- Does the skill request capabilities far beyond its stated purpose?
- Does any skill write to or modify agent memory/instruction files (SOUL.md, MEMORY.md, CLAUDE.md, AGENTS.md,
.cursorrules, .codex/instructions.md, ~/.claude/CLAUDE.md) without a documented reason?
- Does the skill modify shell/profile files (
.bashrc, .zshrc, .profile, .bash_profile, ~/.config/fish/config.fish, PowerShell $PROFILE)?
- Does the skill contain obfuscated code, encoded payloads, or runtime-decoded strings (
base64 -d, eval, exec, Function(...), setTimeout(string))?
- Is the skill publisher verified and trusted (signed commits, verified domain, established history)?
- Are there unexplained network calls to external endpoints (especially raw IPs, DNS-over-HTTPS, paste sites, Discord/Telegram webhooks)?
- Does the skill access credential stores, SSH keys, wallet files, browser cookie DBs, or OS keychain?
- Does the skill markdown body contain instructions aimed at the LLM that conflict with its stated purpose (prompt injection in the skill itself)?
Red flags — capability mismatch:
- Skill description says "note-taking" but requests shell execution
- Skill description says "formatter" but
allowed-tools includes Bash, WebFetch, or write access
- Skill description says "read-only" but contains
Write/Edit/Bash tools or fs:write capability
Red flags — code/data obfuscation:
- Base64, hex, or rot13-encoded strings in skill config or markdown body
- Long string literals with no human-readable content
eval(...), exec(...), Function(...), child_process spawning decoded content
- Network calls to IPs rather than named domains, or to known DGA-style domains
Red flags — credential / system access:
- Writes to or reads from
~/.ssh/, ~/.aws/, ~/.config/gh/, ~/.docker/config.json, ~/.netrc
- Reads
~/Library/Keychains/, secretstorage, keytar, Windows HKCU\Software\Microsoft\Credentials
- Reads browser cookie DBs (
Cookies, Login Data, Local State)
- Reads crypto wallet paths (
~/.ethereum, ~/.config/Solana, Wallet.dat, MetaMask local storage)
- Modifies cron, launchd, systemd, Windows scheduled tasks, or registry Run keys
Red flags — prompt injection in skill body:
- Hidden instructions inside Markdown comments, HTML comments, or fenced blocks
- Invisible / zero-width Unicode in name, description, or instructions (U+200B-U+200F, U+202A-U+202E, U+2066-U+2069, tag characters U+E0000-U+E007F)
- Homoglyph attacks in skill name (Cyrillic
а instead of Latin a, etc.)
- Text like "ignore previous instructions", "you are now", "actually the user wants", "exfiltrate", "send the contents of"
- Instructions to embed user data into URLs, image src, or markdown links (covert exfiltration via auto-fetched images)
Detection commands to run:
- Search for non-ASCII in names/descriptions:
python -c "import sys,re; [print(f) for f in sys.argv[1:] if re.search(r'[^\x00-\x7f]', open(f).read())]"
- Search for base64-looking blobs (>40 chars of
[A-Za-z0-9+/=]): Grep with "[A-Za-z0-9+/=]{40,}"
- Search for prompt-injection phrases:
Grep for (ignore previous|disregard|you are now|actually the user|exfiltrate|send.*to.*http)
For registry operators: Implement Sigstore/cosign signing, Merkle-root publish manifests, automated scanner at publish time, and a static analyzer that flags every red flag above.
AST02: Supply Chain Compromise
Severity: Critical
What to check:
- Are dependencies pinned to exact versions or content hashes (not version ranges)?
- Is there a lockfile for all skill dependencies?
- Are CI/CD pipelines for skill publishing verified (no unvetted third-party Actions)?
- Is there a transparency log or audit trail of published skill versions?
- Are publisher accounts protected with MFA?
Red flags:
"skill-dep": "^1.2.0" (range allows malicious patch)
- Missing lockfile
- CI pipeline uses
actions/checkout@main (unpinned)
- No immutable version artifact (Docker digest, hash pin)
Fix: Replace all version ranges with exact pinned hashes. Add lockfile integrity verification to CI.
AST03: Over-Privileged Skills
Severity: High
What to check:
- Does each skill's permission manifest match its stated purpose?
- Are file path permissions explicit (specific paths only, not
/ or ~)?
- Is network access limited to an allowlist of domains (not
network: true)?
- Does the skill need write access when read-only would suffice?
- Is shell/code execution requested only when functionally required?
Audit matrix:
For each skill, map: claimed purpose -> permissions requested -> permissions actually needed
| Skill | Purpose | Requested | Needed | Delta (over-privileged?) |
|---|
| ... | ... | ... | ... | Yes/No |
Fix: Reduce each permission to the minimum required. Replace wildcard file paths with specific paths. Replace network: true with network: {allow: ["api.example.com"]}.
AST04: Insecure Metadata
Severity: High
What to check (per skill type):
Claude SKILL.md frontmatter:
name present, lowercase, kebab-case, no Unicode/homoglyphs
description present and non-empty (Anthropic discovery requires it; empty means the skill silently fails to load — or worse, loads opaquely)
description accurately summarizes capability, including tool/permission scope
allowed-tools is explicit (no * / all) and matches what the body actually uses
argument-hint matches actual usage
- No conflicting fields (e.g.
allowed-tools: [Read] but body invokes Bash)
MCP server config (mcp.json, claude_desktop_config.json):
command and args are inspectable (no curl | sh style bootstrappers)
env does not embed plaintext secrets
- Server has a verifiable origin (npm package with provenance, signed binary, or local path)
OpenAI plugin (ai-plugin.json):
name_for_model, name_for_human, description_for_model, description_for_human all present and consistent
auth type is appropriate (no none for write-capable plugins)
api.url uses HTTPS and a verified domain
General:
- Is the skill name or description impersonating a known brand or trusted publisher (typosquats:
clade-code, anthropci)?
- Does the skill have a
risk_tier declaration (L0 = read-only to L3 = irreversible/high-impact)?
- Is publisher identity verifiable (signed commit, verified npm publisher, signed container)?
- Are capability declarations honest (does the skill do more than stated)?
Red flags:
- Skill named "google-search" published by an unknown author
- No
risk_tier declaration on a write-capable or shell-capable skill
- Description says "reads files" but code shows
WebFetch/network calls
- Publisher email does not match the claimed organization
- Frontmatter
description is missing, blank, or just the skill name repeated
allowed-tools is absent on a skill that uses Bash/Write/Edit/WebFetch
- Skill name contains characters that visually match a popular skill but differ in code point
Fix: Add risk_tier, verify publisher identity, audit description accuracy against actual code, set allowed-tools to the minimal explicit list, normalize name to ASCII kebab-case.
AST05: Unsafe Deserialization
Severity: High
What to check:
- Are YAML config files parsed with safe parsers (no
!!python/object, !!python/object/apply, !!ruby/object, !!js/function tags)?
- Is JSON input validated against a strict schema (JSON Schema / Zod / Pydantic) before processing?
- Are Markdown frontmatter parsers configured to disallow custom YAML tags?
- Are skill config files loaded from trusted paths only (no loading from
/tmp, downloaded directories, or skill working dirs)?
- Is
pickle / marshal / cloudpickle used anywhere on untrusted input? (Always unsafe.)
- Are XML configs parsed with XXE protection (no external entity expansion)?
- Are TOML files parsed with a spec-compliant parser (no eval)?
- On macOS, are
plist files parsed in binary or XML mode only — never via NSKeyedUnarchiver on untrusted data?
Check YAML parsers in use:
- Python PyYAML:
yaml.safe_load() / yaml.load(..., Loader=yaml.SafeLoader) are safe. yaml.load() without an explicit Loader, or Loader=yaml.Loader / yaml.FullLoader (FullLoader had RCE before PyYAML 5.4), are unsafe. ruamel.yaml default is safe (YAML(typ='safe')); YAML(typ='unsafe') is RCE.
- Python (other):
pickle.load, marshal.loads, shelve, dill, jsonpickle on untrusted input — all RCE.
- Node.js js-yaml: v4+
yaml.load() uses DEFAULT_SCHEMA which does not include !!js/function and is safe for config. v3 yaml.load() accepted !!js/function and was RCE; v3 code must use yaml.safeLoad(). The safest explicit choice is yaml.load(s, { schema: yaml.FAILSAFE_SCHEMA }) (strings/lists/maps only). Avoid the deprecated js-yaml@3 entirely.
- Node.js (other):
node-serialize.unserialize is RCE; serialize-javascript is safe for serialization but eval-ing its output is RCE. yaml package (eemeli/yaml) is safe by default.
- Ruby:
YAML.safe_load() / Psych.safe_load() are safe. YAML.load() / Marshal.load() on untrusted input are RCE.
- Go:
gopkg.in/yaml.v3 is safe by default. encoding/gob on untrusted input is RCE.
- Markdown frontmatter:
gray-matter defaults to js-yaml v4 (safe). front-matter package — verify version. python-frontmatter uses PyYAML safe_load (safe).
Detection commands:
Grep for yaml.load\( (without safe_), pickle.load, Marshal.load, unserialize, eval\(, new Function
Grep for YAML tags in config files: !!python/, !!ruby/, !!js/, !!java/, !<tag:
- Verify all
js-yaml deps are ^4 or later in lockfiles
Fix: Replace unsafe parsers with safe equivalents. Add JSON Schema / Zod / Pydantic validation on all skill config inputs. Never deserialize pickle/Marshal/gob from skill-controlled sources. Upgrade js-yaml@3 to js-yaml@4.
AST06: Weak Isolation
Severity: High
What to check:
- Does the skill platform execute skills in sandboxed containers or isolated processes?
- Can a skill access the host file system outside its declared scope?
- Can a skill access or modify other skills' memory or config?
- Is network egress filtered and logged?
- Are skills that require shell access explicitly marked and sandboxed?
Red flags:
- Skills execute with the same UID as the host agent process
- No seccomp/AppArmor/namespace isolation
- Skills can read
~/.ssh/, ~/.aws/, or other credential directories
- No egress firewall on skill network calls
For skill platforms: Default to container/Docker sandbox. Apply seccomp profile. Mount only declared file paths. Filter all egress through an allowlist proxy.
AST07: Update Drift
Severity: Medium
What to check:
- Are all installed skills pinned to immutable hashes (git SHA, npm
--integrity=sha512-..., Docker digest @sha256:...) — not version ranges or tags like latest/main?
- Is there an inventory tracking installed skill versions across every machine/agent where they run?
- Is there an approval workflow for skill updates (PR required, two-person review for L2+ skills)?
- Are skills monitored for new CVEs or supply chain alerts (Dependabot, Renovate, OSV-Scanner, GitHub Advisory)?
- Is there a maximum allowed age before a skill must be re-reviewed (e.g. 90 days)?
- Does the skill auto-update from a marketplace at runtime? If yes, is the update signature verified? Is there a TOFU pin?
- For MCP servers: is
npx -y package@latest used (auto-updates silently)? Replace with pinned version.
- Is there a rollback path if a malicious update is detected?
For each installed skill: Record current version/hash, source URL, last review date, last update date, next review date, who approved the last update.
Red flags:
npx -y @some/mcp-server in MCP config (pulls latest on every launch)
docker run image:latest in skill bootstrap
- Skill auto-update endpoint with no signature check
- No record of when a skill was last reviewed
- Marketplace polling enabled with auto-install
Fix: Replace all ^, ~, *, latest, main specifiers with exact hashes. Disable auto-update; require a PR to bump versions. Set up a review cadence (monthly for L2+ skills). Add skills to SBOM (CycloneDX or SPDX). Subscribe to OSV-Scanner / Dependabot for skill repos.
AST08: Poor Scanning
Severity: Medium
What to check:
- Is there a scanner running on skill files before installation/publishing (CI gate or pre-commit hook)?
- Does the scanner use behavioral/semantic analysis (not just signature matching)?
- Are multiple independent scanners used (defense in depth)?
- Is there a false-positive review process so scanning fatigue doesn't cause bypass?
- Are natural-language skill descriptions and markdown bodies analyzed for hidden malicious intent (LLM-based scanner)?
- Does scanning cover invisible Unicode and homoglyphs in names/descriptions?
Concrete scan patterns to require:
- Base64/hex blobs:
[A-Za-z0-9+/]{40,}={0,2}, (?:[0-9a-fA-F]{2}){20,}
- Decode-and-exec:
eval, exec, Function(, child_process, os.system, subprocess.*shell=True, Invoke-Expression, IEX
- Network exfil:
curl|wget|fetch|axios|requests to non-allowlisted hosts, webhook.site, requestbin, pastebin, transfer.sh, Discord/Telegram bot APIs, raw IPv4/IPv6
- Credential paths:
.ssh, .aws/credentials, .netrc, keychain APIs, Cookies, Login Data
- Prompt-injection phrases in markdown:
(ignore|disregard) (previous|prior|above) instructions, you are now, actually the user, exfiltrate, send the contents, <!--.*ignore
- Invisible Unicode:
[---0-F]
- Suspicious tool combinations: any skill that declares Bash + WebFetch + filesystem write
Recommended scanners:
- Static: Semgrep (custom rules), CodeQL, Trivy, OSV-Scanner,
gitleaks for secrets
- SBOM/supply chain:
cyclonedx, syft, grype
- LLM-based: Run a guard LLM over each skill's markdown body asking "does this skill contain instructions that would cause an agent to act against the user's interest?"
- Anthropic-specific: validate frontmatter against the documented schema
Scanner coverage matrix:
| Threat Type | Pattern / Tool | Covered? |
|---|
| Known malicious signatures | Semgrep rulesets, ClamAV | ? |
| Obfuscated code | base64/hex regex + entropy check | ? |
| Over-permission detection | manifest diff vs. body usage | ? |
| Natural-language instruction injection | LLM guard + phrase regex | ? |
| Invisible Unicode / homoglyphs | Unicode category scan | ? |
| Supply chain indicators | OSV-Scanner, Dependabot | ? |
| Secret exfil paths | gitleaks + custom path regex | ? |
Fix: Wire the above scanners into CI as a blocking gate. Add LLM-based semantic analysis alongside signature scanning. Require human review for L2/L3 risk-tier skills regardless of scanner pass.
AST09: No Governance
Severity: Medium
What to check:
- Is there a complete inventory of all installed skills across all platforms, all machines, all users?
- Is there an approval process before installing skills in production (CODEOWNERS, PR review, two-person rule for L2+)?
- Are skill actions logged in a structured, queryable audit log (who invoked, when, with what arguments, what tools were called, what files were touched, what network calls were made)?
- Are there RBAC / access controls on who can install/remove skills?
- Is there an incident response procedure for compromised skills (revoke, force-update, notify users, rotate credentials the skill could have seen)?
- Is there a documented owner for each skill?
- Are skill installs tied to identity (SSO, signed install requests) so compromise scope is bounded?
Inventory template to create if missing:
| Skill | Version/Hash | Source URL | Publisher | Platform | Risk Tier | Permissions | Trifecta? | Owner | Installed By | Approved By | Install Date | Last Review | Next Review |
|---|
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
Incident response playbook (must exist):
- Detect — alert source (scanner, user report, CVE)
- Contain — disable skill across all installs, revoke any tokens it could have used
- Assess — what data could it have seen? what actions could it have taken?
- Rotate — credentials, API keys, tokens within the skill's blast radius
- Notify — affected users, downstream dependents, registry if third-party
- Recover — verified clean version, post-mortem, scanner rule update
Fix: Create skill inventory file (e.g. /security/skill-inventory.md). Define approval workflow in CODEOWNERS + CONTRIBUTING.md. Add structured audit logging for all skill invocations. Document the incident response playbook above.
AST10: Cross-Platform Reuse
Severity: Medium
What to check:
- When skills are ported between platforms, is all security metadata preserved end-to-end?
- Do permission manifests survive the conversion (Claude
allowed-tools -> MCP capabilities -> OpenAI plugin auth/api -> LangChain tool args)?
- Is risk tier preserved across platform boundaries?
- Is there tracking of a skill's provenance (original source, signing identity, all platforms it appears on)?
- Does the conversion process re-sign the artifact, or does it lose the original signature?
- Are platform-specific safety features (Claude's
allowed-tools allowlist, OpenAI's auth: oauth, MCP's resource scoping) mapped when absent in the target platform, or silently dropped?
Known translation pitfalls:
- Claude
allowed-tools: [Read] -> MCP server with no equivalent tool restriction -> skill can do anything the server can
- OpenAI plugin
auth.type: oauth -> LangChain Tool(...) with no auth -> bypassed authorization
- MCP
roots (filesystem scope) not represented in Claude allowed-tools -> over-broad file access on port
- Risk tier in source format dropped because target format has no equivalent field
- Description rewritten by an LLM during port, losing safety caveats
Red flags:
- Skill exported from one platform loses its
network: deny constraint
- Risk tier not carried over in the converted format
- Same skill appears on multiple registries with inconsistent permissions or descriptions
- Conversion tool runs unattended with no diff review
Universal Skill Format (USF) — minimal portability schema:
Adopt a YAML envelope that travels with the skill regardless of target platform. Required fields:
usf_version: "1.0"
name: kebab-case-name
display_name: Human Readable Name
version: 1.2.3
content_hash: sha256:...
publisher:
name: Acme Co
identity: did:web:acme.example
signature: <detached sig over content_hash>
description: One sentence, accurate, complete.
risk_tier: L0 | L1 | L2 | L3
capabilities:
filesystem:
read: ["./docs/**"]
write: []
network:
egress: ["api.example.com"]
shell: false
subprocess: []
tools_required: [Read, Grep]
trifecta:
private_data: false
untrusted_content: false
external_comms: false
provenance:
source_url: https://github.com/acme/skill
source_commit: abc123
ported_from: null
review:
last_reviewed: 2026-05-01
reviewer: security@acme.example
next_review: 2026-08-01
Fix: Adopt USF (above) as the canonical envelope. Generate per-platform manifests (SKILL.md, ai-plugin.json, mcp.json, LangChain wrapper) from the USF, never by hand-editing the target format. Validate metadata completeness and signature verification after each platform conversion. Block ports that would drop a capability constraint without an explicit override.
Phase 4: Report
Generate /security/agentic-skills-audit.md:
# OWASP Agentic Skills Top 10 Audit
**Date:** <today>
**Skills Audited:** N
**Platforms:** <from interview>
**Overall Risk:** Critical | High | Medium | Low
## Lethal Trifecta Summary
| Skill | Private data | Untrusted content | External comms | Trifecta? |
|-------|--------------|--------------------|----------------|-----------|
| ... | ... | ... | ... | ... |
## Risk Summary
| ID | Category | Severity | Status | Issues |
|----|----------|----------|--------|--------|
| AST01 | Malicious Skills | Critical | Pass/Findings | N |
| AST02 | Supply Chain Compromise | Critical | ... | N |
| AST03 | Over-Privileged Skills | High | ... | N |
| AST04 | Insecure Metadata | High | ... | N |
| AST05 | Unsafe Deserialization | High | ... | N |
| AST06 | Weak Isolation | High | ... | N |
| AST07 | Update Drift | Medium | ... | N |
| AST08 | Poor Scanning | Medium | ... | N |
| AST09 | No Governance | Medium | ... | N |
| AST10 | Cross-Platform Reuse | Medium | ... | N |
## Critical Findings (fix immediately)
...
## High Findings (fix before next release)
...
## Medium Findings (fix within 30 days)
...
## Skill Inventory (generated)
| Skill | Version/Hash | Source | Risk Tier | Trifecta? | Over-Privileged? | Last Review |
|-------|--------------|--------|-----------|-----------|------------------|-------------|
...
## Governance Gaps
...
## Remediation Checklist
- [ ] Pin all dependencies to hashes
- [ ] Add risk tier to all skills
- [ ] Add `allowed-tools` to all Claude skills
- [ ] Break any Lethal Trifecta chain
- [ ] Upgrade `js-yaml@3` to `@4`, replace `yaml.load()` with safe variants
- [ ] Create skill inventory file
- [ ] Document incident response playbook
- [ ] ...
Phase 5: Fix (if findings found)
For each Critical and High finding, implement the specific fix:
- Replace version ranges with hashes in dependency files
- Reduce permission manifests to minimum required
- Add risk tier declarations to skill metadata
- Replace unsafe YAML parsers
- Create skill inventory file
- Add approval workflow documentation to CLAUDE.md or equivalent
Do not change skill functionality, only security posture.
Completion
List every file changed. Note any findings requiring infrastructure changes (sandbox setup, registry scanner) that cannot be fixed in skill files alone.