Dekita

A skill is instructions plus scripts that run as you. Audit the folder first.

ai agents security devtools

Before you install an Agent Skill, run this. One script, no dependencies, about ten seconds:

#!/usr/bin/env bash
# skill_audit.sh - answer one question before installing an Agent Skill:
#   "What can this folder actually do on my machine?"
#
# Usage: ./skill_audit.sh <skill-dir>
# Exit: 0 = no flags, 1 = flags found (read them, then decide), 2 = could not run.
#
# Contract checks follow the published specification (agentskills.io/specification):
# name 1-64 chars, lowercase alnum with single hyphens, must match the folder;
# description 1-1024 chars; scripts/ holds executable code the agent runs.

set -u

DIR="${1:-}"
[ -n "$DIR" ] && [ -d "$DIR" ] || { echo "usage: $0 <skill-dir>" >&2; exit 2; }

SKILL="$DIR/SKILL.md"
[ -f "$SKILL" ] || { echo "STRUCT: no SKILL.md under $DIR" >&2; exit 2; }

FLAGGED=0
flag() { echo "FLAG: $1"; FLAGGED=1; }

# --- 1. frontmatter contract (spec) ---------------------------------------
NAME="$(sed -n 's/^name:[[:space:]]*//p' "$SKILL" | head -1 | tr -d '\r' | sed 's/^"\(.*\)"$/\1/')"
DESC="$(sed -n 's/^description:[[:space:]]*//p' "$SKILL" | head -1 | tr -d '\r' | sed 's/^"\(.*\)"$/\1/')"
FOLDER="$(basename "$DIR")"

[ -n "$NAME" ] || flag "name missing from frontmatter"
if [ -n "$NAME" ]; then
  echo "$NAME" | grep -qE '^[a-z0-9]+(-[a-z0-9]+)*$' \
    || flag "name '$NAME' is not lowercase alnum with single hyphens"
  [ "${#NAME}" -le 64 ] || flag "name longer than 64 characters"
  [ "$NAME" = "$FOLDER" ] || flag "name '$NAME' does not match folder '$FOLDER'"
fi
[ -n "$DESC" ] || flag "description missing from frontmatter"
[ "${#DESC}" -ge 1 ] && [ "${#DESC}" -le 1024 ] || flag "description outside the 1-1024 range"

# --- 2. what executable code ships in the folder ---------------------------
if [ -d "$DIR/scripts" ]; then
  COUNT="$(find "$DIR/scripts" -type f | wc -l)"
  echo "SHIPS: $COUNT file(s) under scripts/:"
  find "$DIR/scripts" -type f | sed "s|^|  |"
else
  echo "SHIPS: no scripts/ directory"
fi

# --- 3. files the instructions point at actually exist ---------------------
MISSING=0
for ref in $(grep -oE '(scripts|references|assets)/[A-Za-z0-9_./-]*[A-Za-z0-9]' "$SKILL" | sort -u); do
  [ -e "$DIR/$ref" ] || { echo "FLAG: SKILL.md references missing file: $ref"; MISSING=1; }
done
[ "$MISSING" -eq 1 ] && FLAGGED=1

# --- 4. loud patterns in code; concealment phrasing in instructions --------
# A pattern error must fail closed: grep exits 2 on a broken expression, and
# "no output" must never be read as "nothing found" when the scan itself broke.
LOUD='curl|wget|http://|https://|[.]ssh|id_rsa|keychain|AWS_SECRET|AWS_ACCESS|base64 -d|base64 --decode|[^a-z]eval |exec\(|crontab|systemctl|launchctl'
if [ -d "$DIR/scripts" ]; then
  OUT="$(grep -rInE "$LOUD" "$DIR/scripts" 2>/dev/null)"; RC=$?
  if [ "$RC" -gt 1 ]; then
    flag "loud-pattern scan errored; fix the pattern, do not trust the silence"
  elif [ -n "$OUT" ]; then
    echo "$OUT" | sed "s|^|FLAG: script pattern |"
    FLAGGED=1
  else
    echo "OK: no network / credential / obfuscation / persistence patterns in scripts/"
  fi
else
  echo "SKIP: no scripts/ directory to scan"
fi

HIDE='ignore (all |any )?(previous|prior) instructions|do not (tell|inform|show) the user|without (asking|telling) the user'
OUT="$(grep -rInEi "$HIDE" "$DIR" 2>/dev/null)"; RC=$?
if [ "$RC" -gt 1 ]; then
  flag "concealment scan errored; fix the pattern, do not trust the silence"
elif [ -n "$OUT" ]; then
  echo "$OUT" | sed "s|^|FLAG: instruction |"
  FLAGGED=1
else
  echo "OK: no concealment phrasing found in any file"
fi

# --- 5. declared tool scope -------------------------------------------------
if grep -q '^allowed-tools:' "$SKILL"; then
  echo "NOTE: allowed-tools present (experimental field; support varies by agent)"
else
  echo "NOTE: no allowed-tools field; the skill inherits the agent's full permissions"
fi

[ "$FLAGGED" -eq 0 ] && echo "PASS: contract intact, no loud patterns. Now read the files."
exit $FLAGGED

That is the whole audit. The rest of this post is why each check exists, and what it cannot see.

Why this week

On October 22, 2026, Anthropic donated the Agent Skills standard to the Agentic AI Foundation (AAIF) under the Linux Foundation. The donation covers the name and logo, the GitHub organization, and the agentskills.io domain. The AAIF, co-founded by Anthropic, Block, and OpenAI, already hosts MCP; the same announcement added Open Responses from OpenAI, OpenEnv from Hugging Face, and OpenSandbox from Alibaba, bringing the roster to ten projects.

Anthropic's numbers for the format: more than 70 platforms have integrated it since the standard was published in December 2025, about 1 million skills have been published, and nearly 280 million installs have happened. The proposed roadmap covers versioned releases, a formal proposal process, and security guidance for people who write and install skills. The announcement describes all three as proposed; it gives no date.

What that changes is who owns the specification. What it does not change is what happens when you install a skill. A skill is a folder with a SKILL.md file plus any scripts and reference material it needs. The specification is explicit that scripts/ holds executable code. And the skill runs with the permissions of the agent that loads it: shell access, the filesystem, credentials in the environment, messaging channels, and memory that survives the session.

The measurement of that risk already exists. Snyk's ToxicSkills study, published February 5, 2026, scanned 3,984 skills from ClawHub and skills.sh. 13.4% of them, 534 skills, had at least one critical-severity issue, covering malware distribution, prompt injection, and exposed secrets. At any severity, 36.82%, or 1,467 skills, had at least one security flaw. After human review, Snyk confirmed 76 malicious payloads built for credential theft, backdoor installation, or data exfiltration; 8 of those were still installable at publication. The barrier to publishing, in the report's own words: a SKILL.md file and a GitHub account one week old. No code signing, no security review, no sandbox by default.

The same week, Cloudflare's security-audit-skill spent five days at or near the top of GitHub's trending list. That is the shape of a reviewable skill: a public repository, a stated six-phase workflow, machine-readable verdicts (confirmed, needs_validation, rejected), a MIT license, and a design principle that the agent which checks a finding is never the agent that found it. It installs with one line. Most skills you will meet are not that documented. The script above is for those.

One distinction worth keeping while the story is fresh: the foundation governs the specification, not the distribution channels. The donation announcement creates no official registry and no pre-publication review, and skills keep circulating through third-party catalogs. The format is portable now. The trust decision is still local, which is what the rest of this post is about.

What each check is for

Check 1 is the specification's contract, read off the folder. A name that is not lowercase alphanumeric with single hyphens, or longer than 64 characters, or different from the folder name, is either broken or not written to the standard. The name-must-match-folder rule is the one that matters for typosquatting: from the filesystem side, a lookalike name in a mismatched folder is the cheapest signal you get. Check 1's other half, the 1-1024 character description, is the field the agent reads at startup to decide whether to activate the skill at all. An empty or bloated description is a loading-behavior problem, not a style problem.

Check 2 answers the question people forget to ask: does this folder contain code, and how much. scripts/ is where the specification puts executable code, and that code runs with your permissions. Listing the files takes one second and changes how you read the SKILL.md that follows.

Check 3 is the dangling reference. The instructions point at files in scripts/, references/, and assets/; a reference that does not exist is either sloppiness or a loader that fetches something else at runtime.

Check 4 is the loud-pattern pass over the code only. Network fetchers, SSH and key paths, AWS credential variable names, base64 decoding, eval and exec, and persistence hooks are the shapes that appear in the report's threat taxonomy. They are also shapes that appear in legitimate skills, which is why the output is a FLAG line to read, not a verdict. The concealment-phrasing pass covers the instruction layer: "ignore previous instructions", "do not tell the user", "without asking the user". None of these phrases proves malice; all of them justify opening the file.

Check 5 reads the declared tool scope. allowed-tools is experimental and support varies by agent, so its absence is normal. What matters is knowing that its absence means the skill inherits the agent's full permissions, not a reduced set.

What the script cannot check

The gap that matters is between what a skill documents and what it does. Static inspection of a SKILL.md is not sufficient, because a skill that reads cleanly and fetches code at runtime looks identical to one that does not. That case needs a sandbox and a human reading the fetched content, not a grep.

Three smaller limits, stated so you do not trust the script past its reach:

And the obvious one: this script never executes the skill. It tells you what to read before you do.

Pin what you reviewed

The habit that makes the audit worth anything: install the version you read, not a moving branch. Copy the reviewed folder into your skills directory, or pin the commit, and treat an update the way you treat a dependency upgrade: diff it before it loads. Run anything you are unsure about in a throwaway environment first, without production credentials. And re-read the skill when the description changes, because the description is what the agent matches on, and a broadened description is how a skill written for one task starts showing up in all of them.

Run it over what you already have

The audit is more useful pointed backward than forward. The skills already on your machine were installed before you thought to check them. If your agent keeps them in a skills directory, point the script at every folder in it and read the flags:

for d in .claude/skills/*/ "$HOME"/.claude/skills/*/; do
  [ -d "$d" ] && ./skill_audit.sh "$d"
done

The inventory is the part worth having even when nothing is flagged: a list of what code runs with your permissions, per skill, is the artifact you will want the next time a skill updates itself.

Sources

This post was written with AI assistance. The author is responsible for its content.