Back to skill

Security audit

Skill Security Scanner

Security checks for vulnerabilities and agentic risk

Overview

This skill is a disclosed security scanner, but its install-check controls can be bypassed and it makes persistent blocklist changes, so it should be reviewed before use.

Install only if you are comfortable treating this as an advisory scanner, not a reliable enforcement gate. Do not rely on its allowlist as proof a skill is safe, review any blocklist changes it makes, and prefer a scanner that binds approvals to content hashes and fails closed on scan errors.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (3)

T09 · Insecure Skill Coding Practices

Error
Location
preinstall-check.sh:16
Finding
Allowlist validation can be bypassed through skill-name impersonation or regular-expression injection<![CDATA[ ## Vulnerability Details **File Location**: `preinstall-check.sh`, lines 16-28 **Vulnerability Type**: Improper trust binding and unsafe regular-expression construction **Risk Level**: High ### Vulnerable Code ```bash SKILL_NAME=$(basename "$SKILL_PATH") # Check blocklist first if [ -f "$BLOCKLIST" ] && grep -q "^$SKILL_NAME:" "$BLOCKLIST"; then echo "⛔ BLOCKED: $SKILL_NAME is on the security blocklist" grep "^$SKILL_NAME:" "$BLOCKLIST" echo "" echo "Remove from blocklist to override: $BLOCKLIST" exit 2 fi # Check allowlist (skip audit if verified) if [ -f "$ALLOWLIST" ] && grep -q "^$SKILL_NAME:verified:" "$ALLOWLIST"; then echo "✅ ALLOWED: $SKILL_NAME is on the verified allowlist" grep "^$SKILL_NAME:" "$ALLOWLIST" exit 0 fi ``` ### Technical Analysis The script treats the basename of an untrusted skill directory as sufficient proof that the skill was previously reviewed. Approval is not bound to the skill's canonical path, publisher, or content digest. Any unrelated directory can therefore inherit an existing approval by reusing an allowlisted name. In addition, `SKILL_NAME` is interpolated directly into a `grep` regular expression. Filesystem-valid metacharacters such as `.*` are interpreted as regular-expression syntax rather than literal characters. This can cause a crafted name to match an unrelated allowlist entry. A successful allowlist match immediately exits with status zero and skips `audit.sh`, making this a direct bypass of the advertised pre-installation security control. ### Attack Path 1. Identify an existing allowlisted name, such as `himalaya`, or choose a regex-based name such as `.*`. 2. Create a malicious skill directory using that basename. 3. Invoke `preinstall-check.sh` with the malicious directory. 4. The script extracts only the basename and matches it against `allowlist.txt`. 5. The allowlist branch exits successfully without invoking `audit.sh`. 6. The malicious skill is reported as ...[truncated 506 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Do not use a directory basename as the identity of an approved skill. - Bind each approval to a canonical path and a cryptographic digest of the reviewed skill contents. - Recalculate and verify the digest before every installation or execution. - Parse allowlist records into fields and compare the name as a literal fixed string, for example with `grep -F`, rather than constructing a regular expression. - Validate skill names against a restrictive format such as `^[A-Za-z0-9._-]+$`. - Use exact field equality and reject duplicate or malformed allowlist records. - Consider removing the audit-skipping behavior entirely: an allowlist may suppress a warning after scanning, but it should not prevent changed contents from being scanned. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
audit.sh:28
Finding
Option-like target paths can alter grep behavior and cause incomplete scans<![CDATA[ ## Vulnerability Details **File Location**: `audit.sh`, line 28 **Vulnerability Type**: Improper argument handling and fail-open error suppression **Risk Level**: Medium ### Vulnerable Code ```bash matches=$(grep -rlE "$pattern" "$SKILL_PATH" 2>/dev/null || true) ``` The resulting empty counters are later treated as a successful clean scan: ```bash if [ $CRITICAL -eq 0 ] && [ $HIGH -eq 0 ] && [ $MEDIUM -eq 0 ]; then echo -e "${GREEN}✅ CLEAN - No security issues found${NC}" exit 0 fi ``` ### Technical Analysis `SKILL_PATH` is controlled by the caller and is passed to `grep` without a `--` option terminator. On implementations such as GNU grep, a relative path beginning with `-` can be interpreted as a command-line option instead of a file or directory to scan. The command also discards diagnostics and converts every grep failure into a successful shell result through `2>/dev/null || true`. The scanner therefore cannot distinguish between “no pattern matched” and “the target was not scanned correctly.” If all checks fail or inspect no files, the finding counters remain zero and the script reports the target as clean. ### Attack Path 1. Create or reference a skill through an option-like relative path beginning with `-`. 2. Pass that value as the audit target. 3. `grep` interprets the target as an option rather than as the intended directory. 4. Any resulting diagnostic is suppressed, and `|| true` prevents the failure from stopping the audit. 5. No finding counter is incremented. 6. The final branch can report `CLEAN` even though the intended skill contents were not successfully scanned. ### Impact Assessment The issue permits alteration or evasion of the static scan when an attacker can influence the target path. It does not directly execute attacker-supplied commands or elevate operating-system privileges. Its security impact is the loss of scan integrity: prohibited behavior may remain undetected and an unscanned skill may receive a ...[truncated 22 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Canonicalize the supplied target before scanning and verify that it is an existing directory. - Reject option-like, malformed, inaccessible, or noncanonical target values. - Terminate grep option parsing explicitly: ```bash matches=$(grep -rlE -- "$pattern" "$SKILL_PATH") ``` - Do not suppress all scanner errors or convert them unconditionally to success. - Distinguish grep status `1` for no matches from status `2` for an operational error. - Fail closed and return a nonzero audit status if any file cannot be inspected or any scan command fails. - Record and compare the expected number of files with the number successfully scanned. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
audit.sh:28
Finding
Recursive scan omits content referenced through symbolic links<![CDATA[ ## Vulnerability Details **File Location**: `audit.sh`, line 28 **Vulnerability Type**: Incomplete file traversal **Risk Level**: Medium ### Vulnerable Code ```bash matches=$(grep -rlE "$pattern" "$SKILL_PATH" 2>/dev/null || true) ``` ### Technical Analysis The scanner relies on recursive `grep -r` and does not separately enumerate, reject, or resolve symbolic links. Recursive grep generally does not follow symbolic links encountered while traversing a directory. Consequently, a symlink contained inside a submitted skill can reference executable code or instructions that are not included in the scan. The script also suppresses traversal diagnostics, so omitted or inaccessible entries do not make the audit fail. If a later skill loader follows those links, the effective skill content can differ from the content inspected by the scanner. ### Attack Path 1. Create a skill directory containing apparently benign regular files. 2. Add an internal symbolic link that points to a file or directory containing a prohibited behavior. 3. Submit the containing skill directory to `audit.sh`. 4. Recursive grep omits the linked target while traversing the directory. 5. The scanner reports no finding for the linked content. 6. A subsequent loader or interpreter follows the symlink and consumes or executes the uninspected content. ### Impact Assessment An attacker can conceal relevant code or instructions from the static scanner and create a discrepancy between audited and consumed content. The flaw does not itself follow or execute the symlink and does not independently escalate privileges. The eventual scope depends on how the consuming agent handles symlinks and on the privileges available when the linked content is loaded or executed. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Reject all symbolic links within submitted skill packages unless they are explicitly required and safely validated. - Enumerate directory entries before scanning and use `lstat` or equivalent logic to detect symlinks. - If symlinks must be supported, resolve every target to a canonical path and require it to remain within the canonical skill root. - Scan every accepted resolved target rather than relying solely on recursive grep behavior. - Detect cycles and prevent repeated or unbounded traversal. - Fail closed if a link is broken, inaccessible, points outside the audited root, or cannot be scanned. - Package or copy validated regular files into an isolated directory before installation so the reviewed content cannot later change through an external symlink target. ]]>
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (8)

Credential Access

High
Category
Privilege Escalation
Content
check_pattern "Network Exfiltration" "HIGH" "(requests\.post|requests\.put|urllib\.request\.urlopen|http\.client\.HTTPConnection|fetch\([^)]+{)"
check_pattern "Credential File Access" "HIGH" "(open\([^)]*\.(ssh|aws|gnupg|config)|read.*id_rsa|read.*credentials)"
check_pattern "Password Store Access" "HIGH" "subprocess\.(run|call|Popen).*pass\s+(show|insert)"
check_pattern "Keyring/Keychain Access" "HIGH" "(keyring\.get|SecItemCopyMatching|security find-generic-password)"
check_pattern "Shell Command Injection" "HIGH" "(os\.system\(|subprocess\.[^(]+\([^)]*shell=True.*\+)"

# MEDIUM checks
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
check_pattern "Network Exfiltration" "HIGH" "(requests\.post|requests\.put|urllib\.request\.urlopen|http\.client\.HTTPConnection|fetch\([^)]+{)"
check_pattern "Credential File Access" "HIGH" "(open\([^)]*\.(ssh|aws|gnupg|config)|read.*id_rsa|read.*credentials)"
check_pattern "Password Store Access" "HIGH" "subprocess\.(run|call|Popen).*pass\s+(show|insert)"
check_pattern "Keyring/Keychain Access" "HIGH" "(keyring\.get|SecItemCopyMatching|security find-generic-password)"
check_pattern "Shell Command Injection" "HIGH" "(os\.system\(|subprocess\.[^(]+\([^)]*shell=True.*\+)"

# MEDIUM checks
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
check_pattern "Network Exfiltration" "HIGH" "(requests\.post|requests\.put|urllib\.request\.urlopen|http\.client\.HTTPConnection|fetch\([^)]+{)"
check_pattern "Credential File Access" "HIGH" "(open\([^)]*\.(ssh|aws|gnupg|config)|read.*id_rsa|read.*credentials)"
check_pattern "Password Store Access" "HIGH" "subprocess\.(run|call|Popen).*pass\s+(show|insert)"
check_pattern "Keyring/Keychain Access" "HIGH" "(keyring\.get|SecItemCopyMatching|security find-generic-password)"
check_pattern "Shell Command Injection" "HIGH" "(os\.system\(|subprocess\.[^(]+\([^)]*shell=True.*\+)"

# MEDIUM checks
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Lp3

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding
Without declared permissions the skill's intent is opaque and cannot be validated.

Vague Triggers

Medium
Confidence
94% confidence
Finding
The trigger conditions are very broad and include generic security-related workflows such as skill audit, security scan, and before loading external skill. A broadly auto-triggered skill that suggests shell execution and includes promotional external links can become an over-invoked component in sensitive contexts, increasing the chance of unintended execution, user confusion, or abuse as a socially trusted security authority.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The script is presented as an audit tool, but on CRITICAL findings it also mutates local state by appending entries to a blocklist file. This side effect can surprise users and downstream automation, and it creates an enforcement mechanism that may persist beyond the current scan without explicit consent.

Intent-Code Divergence

Low
Confidence
88% confidence
Finding
The usage/header comments describe a passive audit script, but the implementation performs enforcement-like persistence by maintaining a blocklist. That mismatch can mislead operators about side effects, which is a security-relevant transparency issue in tooling that may be run automatically.

Missing User Warnings

Low
Confidence
95% confidence
Finding
Appending to a local blocklist without user-facing warning or confirmation introduces an undocumented persistent state change. In automated or shared environments this can cause denial of use, audit confusion, or policy drift if entries are added unexpectedly.

Static analysis

No suspicious patterns detected.