Skip to main content

Skill Indicators

Reference

Every point in a skill's risk score traces back to one of the indicators below. This page is the full catalog — grouped by family, with each indicator's severity (static indicators only), default weight, and what it detects.

note

Weights shown here are shipped defaults. Every weight, and the review/blocked band thresholds, are operator-tunable — see Tune skill risk weights. An indicator firing does not by itself mean a skill is blocked; its weight is only one input to the combined score described in Skill Risk.

How to read this table

  • ID — the identifier that appears in a skill's indicator list and in object.skill.indicators for CEL policy matching.
  • Severity — assigned only to static indicators (critical / high / medium / low), reflecting how dangerous the detected pattern is taken at face value. Behavioral indicators don't carry a graded severity — see Behavioral family for why.
  • Default weight — the point value the indicator contributes toward the 0–100 risk score before any operator override.
  • Detects — the specific pattern or condition that fires the indicator.

Shell & script execution

Patterns indicating a skill runs, downloads, obfuscates, or drops executable code.

IDSeverityDefault weightDetects
SHELL_CURL_PIPE_SHcritical40curl | sh / bash / zsh — downloads and immediately executes remote content
SHELL_WGET_PIPE_SHcritical40Same pattern via wget
SHELL_BASE64_DECODE_EXECcritical40Base64-decoded content piped straight into a shell — obfuscated execution
BINARY_DROP_EXECcritical40Download-then-chmod +x chain, or chmod +x/755 against a file in /tmp
POWERSHELL_INVOKE_EXPRESSIONhigh40PowerShell Invoke-Expression / iex
UNSAFE_CODE_EVALhigh25Dynamic code evaluation (eval(, exec(, compile(, __import__(, new Function)
UNSAFE_DESERIALIZATIONhigh25Unsafe deserialization (pickle.load, yaml.unsafe_load, marshal.load, jsonpickle.decode)
INLINE_INTERPRETER_EXECmedium15Inline interpreter invocation (python -c, node -e, bash -c, powershell -Command, ...)
UNEXPECTED_EXECUTABLEmedium15A bundle file has the executable bit set but isn't a recognized script type
SCRIPT_NO_ERROR_HANDLINGmedium0A shell script has no set -e / set -eo pipefail in its first 20 lines
SCRIPT_WRITES_TO_SKILL_DIRmedium0A script writes output into the skill's own directory instead of the caller's working directory
UNICODE_BIDI_CONTROLcritical35Unicode bidirectional control characters — can render code to look different from what it does

Credential & secrets access

Patterns indicating a skill reads credential material.

IDSeverityDefault weightDetects
HARDCODED_CREDENTIALShigh35An inline API key, password, bearer token, or cloud access key literal
SECRETS_CREDENTIAL_FILEcritical35Access to a well-known credential file (~/.aws/credentials, ~/.docker/config.json, ~/.npmrc, ~/.netrc, etc.)
SECRETS_KEYCHAIN_ACCESScritical35macOS Keychain or platform credential-store access
SECRETS_GIT_CREDENTIALScritical35Git credential helper configuration or .git-credentials access
TOUCHES_KUBECONFIGhigh20Reference to KUBECONFIG or ~/.kube/config
TOUCHES_SSH_KEYShigh20Reference to SSH private key material

Network & exfiltration

Patterns indicating a skill reaches out to the network, or moves data toward the network.

IDSeverityDefault weightDetects
DATA_EXFIL_PATTERNcritical35File contents piped directly into a network client (cat file | curl ...)
NET_EXFIL_SINKcritical25A known anonymous-drop destination (webhook.site, requestbin, ngrok, pastebin, a raw Slack/Discord webhook URL)
HARDCODED_CREDENTIALS (network context)(see Credential & secrets access above)
SUSPICIOUS_ENV_EXFILhigh20Environment variables piped into a network client (env | curl ...)
NET_INSECURE_HTTPhigh25A plaintext http:// URL (excluding localhost)
NET_RAW_IP_DESThigh25A raw IP-literal destination, bypassing DNS-based egress controls
NETWORK_ACCESS_PATTERNhigh0Any HTTP client call (curl, wget, requests.*, urllib, Net::HTTP, ...)
MCP_TOOL_REFERENCEmedium0A reference to another MCP tool, extending the skill's effective reach beyond its own declared scope

Prompt injection & instruction manipulation

Patterns indicating a skill's own content tries to manipulate the agent that loads it.

IDSeverityDefault weightDetects
PROMPT_INJECTION_PATTERNcritical35Classic injection phrasing ("ignore previous instructions," "do not tell the user," "jailbreak," ...)
INSTRUCTION_MANIPULATIONcritical35Directives to bypass safety/security checks, or conditional instructions to lie if asked about the skill's behavior
SKILL_FRONTMATTER_XML_TAGSmedium10XML/HTML tags in the name or description frontmatter fields — a possible injection vector if rendered verbatim into a system prompt

Privilege escalation & tampering

Patterns indicating a skill elevates its own privileges or disables host security controls.

IDSeverityDefault weightDetects
SECURITY_DISABLE_FIREWALLcritical40A command that disables the host firewall (ufw disable, iptables -F, pfctl -d, ...)
SECURITY_DISABLE_GATEKEEPERcritical40A command that disables macOS Gatekeeper or SIP
SECURITY_DISABLE_AVcritical40A command that disables or tampers with antivirus/EDR (Windows Defender, CrowdStrike, SentinelOne)
PRIVILEGE_ESCALATION_SUDOcritical35sudo, su, or doas
PRIVILEGE_ESCALATION_SETUIDcritical35chmod +s, an octal mode granting setuid/setgid, chown root, or setcap
PRIVILEGE_ESCALATION_SYSTEM_WRITEcritical35A write to a protected system path (/etc/, /Library/LaunchDaemons, /etc/systemd/system, ...)

Persistence

Patterns indicating a skill installs itself to survive beyond the current session.

IDSeverityDefault weightDetects
PERSISTENCE_SHELL_PROFILEcritical35A write to a shell profile (.bashrc, .zshrc, .profile, ...)
PERSISTENCE_SCHEDULED_TASKcritical35Scheduled-task or service installation (crontab, launchctl, systemctl enable, ...)
PERSISTENCE_GIT_HOOKScritical35Modification of .git/hooks/ or core.hooksPath
ENV_LOADER_INJECTIONcritical30LD_PRELOAD / DYLD_INSERT_LIBRARIES loader injection
ENV_PATH_HIJACKhigh30PATH rewritten to prepend a temp or hidden directory

Container & cluster

Patterns indicating container-escape techniques or unpinned cluster-changing commands.

IDSeverityDefault weightDetects
CONTAINER_ESCAPE_DOCKER_SOCKhigh25Access to the Docker socket (/var/run/docker.sock)
CONTAINER_ESCAPE_NAMESPACEhigh25Namespace-escape tooling (nsenter, unshare, --privileged)
CONTAINER_ESCAPE_HOST_MOUNThigh25A host-root filesystem mount into a container
REMOTE_MANIFEST_APPLYhigh20kubectl apply/create -f against a remote URL, unpinned
REMOTE_HELM_INSTALLhigh20helm install/upgrade against a remote chart URL, unpinned

Dependency hygiene

Patterns indicating a skill's dependency manifests are unpinned or unverifiable.

IDSeverityDefault weightDetects
DEPS_UNPINNEDmedium15A dependency manifest using a version range, *, or latest instead of a pinned version
DEPS_NO_LOCKFILEmedium15A dependency manifest present with no corresponding lockfile in the bundle

Spec conformance

Structural checks against the Agent Skills specification's frontmatter schema — these are hygiene indicators (see the note below), not security threat signals, so all four default to weight 0.

IDSeverityDefault weightDetects
SKILL_MD_MISSINGcritical0SKILL.md absent from the bundle entirely
SKILL_NAME_FORMAT_INVALIDlow0name isn't 1–64 lowercase alphanumeric characters and hyphens
SKILL_NAME_DIR_MISMATCHlow0name doesn't match the bundle's directory name
SKILL_DESCRIPTION_INVALIDlow0description missing or over 1024 characters
note

Indicators are also tagged with a kind of security or hygiene in the Risk Scoring settings UI (Settings → Security & Privacy → Risk Scoring → Skills — see Tune risk weights). Hygiene indicators — the four above, plus SCRIPT_NO_ERROR_HANDLING, SCRIPT_WRITES_TO_SKILL_DIR, NETWORK_ACCESS_PATTERN, and MCP_TOOL_REFERENCE from the tables above — are spec-conformance and code-quality signals rather than security threats, so they default to weight 0: detected and shown as evidence, but not scored, unless an operator re-enables them.

note

Two additional indicator IDs, SYMLINK_OUTSIDE_ROOT and SYMLINK_INTERNAL, are reserved in the weight table for symlink-escape detection but do not currently fire — bundle content is captured as a flat file map with no filesystem symlink metadata. They're listed here only so an operator tuning weights sees the full space; they carry no live risk contribution today.

Behavioral family

Behavioral indicators fire from what agents were observed doing while a skill was active, aggregated over a rolling window — not from the skill's declared content. They're the compensating control for content that reads as safe but behaves otherwise (see Divergence and drift).

Behavioral indicators don't carry a graded severity the way static ones do — there's no equivalent to "this pattern is obviously critical at a glance," because the same underlying action (say, contacting a new host) can be perfectly legitimate or a live exfiltration attempt depending entirely on context the aggregate signal doesn't carry alone. Their entire risk signal is expressed through weight, and several have an operator-tunable trigger threshold.

IDDefault weightTunable thresholdDetects
BEHAV_STATIC_DIVERGENCE35Observed behavior (network, exec, credential access, or writes) falls outside every category the static scan indicated — the strongest single signal, since it can't be gamed by patient behavior alone
BEHAV_CRED_ACCESS35An attributed tool call read a credential-shaped path (kubeconfig, SSH keys, .env, cloud credentials)
BEHAV_EXFIL_COMBO35Credential access and an unrecognized egress host observed in the same window — the two individually-moderate signals compound
BEHAV_EGRESS_UNKNOWN_HOST30A contacted host isn't present in the AI tool catalogue / egress allowlist
BEHAV_TOOL_SCOPE_VIOLATION30The skill declared an allowed-tools scope in its frontmatter, and an attributed call used a tool outside it
BEHAV_DRIFT25New tool categories or new hosts appear versus this digest's own established baseline (see Divergence and drift)
BEHAV_WRITE_BREADTH205 distinct write targetsThe skill wrote to more distinct resources in the window than the threshold
BEHAV_POLICY_FRICTION153 denials/approvalsAttributed calls were denied or routed to human approval more than the threshold in the window
BEHAV_TOOL_BREADTH154 distinct toolsThe skill used more distinct tools in the window than the threshold
BEHAV_CALL_RATE1020 calls/invocationCalls-per-invocation exceeded the threshold — unusually chatty relative to a typical single activation

See also