Back to skill

Security audit

Scan Skill

Security checks for vulnerabilities and agentic risk

Overview

This is a security-scanner skill with mostly purpose-aligned behavior, but it can read outside the chosen skill directory through symlinks and can replay unsafe scanned text into reports.

Install only if you are comfortable running a scanner with Bash that recursively reads the selected skill directory. Run it in a sandbox or on a copy of the target skill with symlinks removed, and treat its generated report as untrusted data because excerpts from hostile skills may be reproduced verbatim. Be aware that package-install findings may trigger outbound checks to PyPI or npm.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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
Findings (2)

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/scan_skill.py:163
Finding
Project Boundary Escape Through Symbolic Links<![CDATA[ ## Vulnerability Details **File Location**: `scripts/scan_skill.py:163-190` and `scripts/scan_skill.py:284-294` **Vulnerability Type**: Symbolic-link traversal and unauthorized file access **Risk Level**: Medium ### Vulnerable Code ```python def Scan_Supporting_Files(skill_dir: Path) -> list[Finding]: """Scan all supporting files in the skill directory.""" findings: list[Finding] = [] # Scan all files in scripts/ and other subdirectories Scannable_Extensions = {".py", ".sh", ".bash", ".js", ".ts", ".rb", ".pl"} for file_path in skill_dir.rglob("*"): if not file_path.is_file(): continue if file_path.name == "SKILL.md": continue str_path = str(file_path) # Check for executable permissions on non-standard files if file_path.suffix not in Scannable_Extensions: try: file_stat = os.stat(file_path) if file_stat.st_mode & (stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH): findings.append(Finding( pattern_name="executable_non_script", severity=Severity.MEDIUM, category=Category.SKILL_INJECTION, description=f"Non-standard file has executable permission: {file_path.name}", file_path=str_path, line_number=0, matched_text=f"mode: {oct(file_stat.st_mode)}", )) except OSError: pass # Scan content of script files if file_path.suffix in Scannable_Extensions: try: content = file_path.read_text(encoding="utf-8", errors="replace") except (PermissionError, OSError): continue ``` The main skill file is read with the same issue: ```python skill_md = skill_dir / "SKILL.md" if not skill_md.exists(): print(f"Error: No SKILL.md found in {skill_dir}", file=sys.stderr) sys.exit(1) print(f"Analyzing skill: {skill_dir}\n") all_findings: list[Finding] = [] str_skill_md = str(skill_md) # Read SKILL.md content = skill_md.read_text(encoding="utf-8", errors="replace") ``` ### Technical Analysis `Path.is_file()`, `Path.exists()`, `Path.read_text()`, and `os.stat()` follo ...[truncated 1920 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Reject symbolic links before reading or statting files: ```python if file_path.is_symlink(): continue ``` - Resolve both the root and every candidate, then enforce containment: ```python root = skill_dir.resolve(strict=True) def safe_resolve(path: Path) -> Path: if path.is_symlink(): raise ValueError(f"Symbolic links are not allowed: {path}") resolved = path.resolve(strict=True) if not resolved.is_relative_to(root): raise ValueError(f"Path escapes skill directory: {path}") return resolved ``` - Apply the same check to `SKILL.md`, all supporting files, and inventory operations. - Prefer file-descriptor-based opening with no-follow semantics where supported, such as `O_NOFOLLOW`, to reduce time-of-check/time-of-use races. - Run the scanner in a sandbox with a read-only view containing only the target directory. Do not expose the user's home directory, SSH directory, cloud credentials, or other unrelated paths. - Add regression tests covering absolute symlinks, relative symlinks, nested symlink chains, broken links, and links changed between validation and opening. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/patterns.py:1319
Finding
Untrusted Scan Payloads Are Reproduced Verbatim in Agent-Visible Reports<![CDATA[ ## Vulnerability Details **File Location**: `scripts/patterns.py:1319-1344` and `scripts/patterns.py:1391-1397`; output is emitted at `scripts/scan_skill.py:325` **Vulnerability Type**: Unsafe rendering of attacker-controlled report content **Risk Level**: Medium ### Vulnerable Code ```python for pattern in patterns: if pattern.compiled is None: continue for match in pattern.compiled.finditer(content): # Calculate line number from match position line_number = content[:match.start()].count("\n") + 1 matched_text = match.group(0) # Truncate long matches for display Max_Match_Display = 200 if len(matched_text) > Max_Match_Display: matched_text = matched_text[:Max_Match_Display] + "..." # Get context lines context = "" if context_lines > 0: start_line = max(0, line_number - 1 - context_lines) end_line = min(len(lines), line_number + context_lines) context = "\n".join(lines[start_line:end_line]) findings.append(Finding( pattern_name=pattern.name, severity=pattern.severity, category=pattern.category, description=pattern.description, file_path=file_path, line_number=line_number, matched_text=matched_text, context=context, )) ``` The captured text is inserted directly into Markdown: ```python for finding in severity_findings: report_lines.append( f"- **[{finding.severity.value}]** {finding.description}\n" f" - File: `{finding.file_path}:{finding.line_number}`\n" f" - Pattern: `{finding.pattern_name}`\n" f" - Match: `{finding.matched_text}`" ) report_lines.append("") ``` The report is then printed: ```python report = Format_Report( title="scan-skill", scanned_target=str(skill_dir), findings=unique_findings, ) print(report) ``` ### Technical Analysis The scanner is explicitly designed to process potentially malicious instructions and prompt-injection payloads. Nevertheless, regex matches taken from untrusted files are inserted into a Markdown report without escaping Markdow ...[truncated 2003 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Treat every scanned excerpt as hostile data. - Escape backticks, backslashes, carriage returns, line breaks, and other Markdown metacharacters before interpolation. - Replace terminal control characters with visible escaped forms such as `\x1b`, `\r`, and `\n`. - Prefer a deterministic encoded representation, such as JSON escaping: ```python import json def safe_excerpt(value: str, limit: int = 200) -> str: value = value[:limit] return json.dumps(value, ensure_ascii=True) ``` - Clearly delimit excerpts with fixed trusted markers and state that their contents must never be interpreted as instructions. - For agent-facing output, report the pattern name, location, hash, and a minimal escaped excerpt rather than reproducing complete injection payloads. - Offer full raw evidence only through a separate file that is not automatically inserted into model context. - Sanitize `file_path` and other values derived from the scanned directory as well. - Add tests for embedded backticks, ANSI escape sequences, carriage-return rewriting, multiline matches, Markdown links and images, XML-like instructions, and prompt-injection text. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
Findings (50)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The skill is presented as analyzing a single skill directory, but the documented behavior and referenced scanner capabilities suggest broader repository and environment inspection, including external package verification and multi-tool post-processing. This scope mismatch is dangerous because users may grant trust, inputs, or execution based on a narrowly described purpose while the skill operates on a much larger attack and privacy surface than expected.

Lp1

High
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The file implements live network access via urllib to query PyPI and npm, so the static finding about undeclared network capability is substantively correct. In a skill whose stated purpose is local skill analysis, undisclosed outbound access expands the trust boundary, can leak metadata about what is being scanned, and may violate least-privilege expectations.

YARA rule 'agent_skill_prompt_injection_hidden_instructions': Prompt injection or hidden instructions embedded in AI agent skill text [agent_skills]

High
Category
YARA Match
Content
"""
Shared pattern database for AI Agent Security skill suite.

Central registry of detection patterns derived from research notes 01-18
and examples 01-04. Used by vet-repo, scan-skill, and audit-code skills.
"""

import re
from dataclasses import dataclass, field
from enum import Enum
from typing import Optional


class Severity(Enum):
	CRITICAL = "CRITICAL"
	HIGH = "HIGH"
	MEDIUM = "MEDIUM"
	LOW = "LOW"
	INFO = "INFO"


class Category(Enum):
	SKILL_INJECTION = "skill_injection"
	HOOK_ABUSE = "hook_abuse"
	MCP_CONFIG = "mcp_config"
	SECRETS = "secrets"
	DANGEROUS_CALLS = "dangerous_calls"
	EXFILTRATION = "exfiltration"
	EN
Confidence
80% confidence
Finding
YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

YARA rule 'agent_skill_mcp_tool_poisoning_metadata': MCP/tool metadata poisoning indicators in tool schemas or skill manifests [agent_skills]

High
Category
YARA Match
Content
_obfuscation"
	INSTRUCTION_OVERRIDE = "instruction_override"
	SUPPLY_CHAIN = "supply_chain"
	FILE_PERMISSIONS = "file_permissions"
	CODE_BEFORE_REVIEW = "code_before_review"
	CONFIG_BACKDOOR = "config_backdoor"
	MEMORY_CORRUPTION = "memory_corruption"
	CONFUSED_DELEGATION = "confused_delegation"
	PERSISTENCE = "persistence"


@dataclass
class Pattern:
	name: str
	pattern: str
	severity: Severity
	description: str
	category: Category
	compiled: Optional[re.Pattern] = field(default=None, repr=False)

	def __post_init__(self) -> None:
		self.compiled = re.compile(self.pattern, re.IGNORECASE)


@dataclass
class Finding:
	pattern_name: str
	severity: Severity
	category: Category
	description: str
	file_path: str
	line_number: int
	matched_text: str
	context: str = ""


# -- Skill Injection Patterns --

Skill_Injection_Patterns: list[Pattern] = [
	Pattern(
		name="html_comment_with_commands",
		pattern=r"<!--[\s\S]*?(curl|wget|bash|sh|exec|eval|system|python|node|perl)[\s\S]*?-->",
		severit
Confidence
80% confidence
Finding
YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

Credential Access

High
Category
Privilege Escalation
Content
name="github_pat",
		pattern=r"gh[pso]_[a-zA-Z0-9]{36,}",
		severity=Severity.CRITICAL,
		description="GitHub personal access token detected",
		category=Category.SECRETS,
	),
	Pattern(
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
name="github_pat",
		pattern=r"gh[pso]_[a-zA-Z0-9]{36,}",
		severity=Severity.CRITICAL,
		description="GitHub personal access token detected",
		category=Category.SECRETS,
	),
	Pattern(
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Obfuscated Code

High
Category
Supply Chain
Content
name="python_marshal_loads",
		pattern=r"marshal\.loads\s*\(",
		severity=Severity.MEDIUM,
		description="marshal.loads() -- deserializes Python code objects, rarely needed in normal code",
		category=Category.DANGEROUS_CALLS,
	),
	# Java / .NET / PowerShell
Confidence
90% confidence
Finding
Code contains obfuscation (base64, hex encoding with execution). This is often used to hide malicious functionality.

Obfuscated Code

High
Category
Supply Chain
Content
name="python_marshal_loads",
		pattern=r"marshal\.loads\s*\(",
		severity=Severity.MEDIUM,
		description="marshal.loads() -- deserializes Python code objects, rarely needed in normal code",
		category=Category.DANGEROUS_CALLS,
	),
	# Java / .NET / PowerShell
Confidence
90% confidence
Finding
Code contains obfuscation (base64, hex encoding with execution). This is often used to hide malicious functionality.

YARA rule 'info_stealer': Information stealer patterns (credential harvesting, browser data theft) [malware]

High
Category
YARA Match
Content
TUP|NODE_OPTIONS|GIT_SSH_COMMAND|PYTHONPATH|RUBYOPT|JAVA_TOOL_OPTIONS)\s*=",
		severity=Severity.HIGH,
		description="Environment variable hijack -- can intercept library loads, force code execution, or redirect commands",
		category=Category.DANGEROUS_CALLS,
	),
	# Credential store access
	Pattern(
		name="crypto_wallet_browser_creds",
		pattern=r"(Exodus|MetaMask|Electrum|wallet\.dat|Login Data|Cookies|Web Data|chrome.*User Data|\.mozilla/firefox)",
		severity=Severity.HIGH,
		description="Crypto wallet or browser credential store access -- credential harvesting indicator",
		category=Category.DANGEROUS_CALLS,
	),
]


# -- Exfiltration Patterns --

Exfiltration_Patterns: list[Pattern] = [
	Pattern(
		name="curl_post_sensitive_file",
		pattern=r"curl\s+[^\n]*(-d|--data)\s+[^\n]*(cat|<)\s+[^\n]*(\.ssh|\.aws|\.gnupg|\.kube|\.env|credentials|id_rsa|private)",
		severity=Severity.CRITICAL,
		description="Exfiltration -- sensitive file contents sent via curl POST",
		category=Category.EXFI
Confidence
75% confidence
Finding
YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Credential Access

High
Category
Privilege Escalation
Content
),
	Pattern(
		name="sensitive_file_read",
		pattern=r"(cat|head|tail|less|more|type)\s+[^\n]*(\.ssh/id_rsa|\.aws/credentials|\.gnupg/|\.kube/config|/etc/shadow|/etc/passwd)",
		severity=Severity.HIGH,
		description="Reading sensitive credential files",
		category=Category.EXFILTRATION,
Confidence
90% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
),
	Pattern(
		name="sensitive_file_read",
		pattern=r"(cat|head|tail|less|more|type)\s+[^\n]*(\.ssh/id_rsa|\.aws/credentials|\.gnupg/|\.kube/config|/etc/shadow|/etc/passwd)",
		severity=Severity.HIGH,
		description="Reading sensitive credential files",
		category=Category.EXFILTRATION,
Confidence
90% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
),
	Pattern(
		name="sensitive_file_read",
		pattern=r"(cat|head|tail|less|more|type)\s+[^\n]*(\.ssh/id_rsa|\.aws/credentials|\.gnupg/|\.kube/config|/etc/shadow|/etc/passwd)",
		severity=Severity.HIGH,
		description="Reading sensitive credential files",
		category=Category.EXFILTRATION,
Confidence
80% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
),
	Pattern(
		name="sensitive_file_read",
		pattern=r"(cat|head|tail|less|more|type)\s+[^\n]*(\.ssh/id_rsa|\.aws/credentials|\.gnupg/|\.kube/config|/etc/shadow|/etc/passwd)",
		severity=Severity.HIGH,
		description="Reading sensitive credential files",
		category=Category.EXFILTRATION,
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
),
	Pattern(
		name="sensitive_file_read",
		pattern=r"(cat|head|tail|less|more|type)\s+[^\n]*(\.ssh/id_rsa|\.aws/credentials|\.gnupg/|\.kube/config|/etc/shadow|/etc/passwd)",
		severity=Severity.HIGH,
		description="Reading sensitive credential files",
		category=Category.EXFILTRATION,
Confidence
95% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
),
	Pattern(
		name="sensitive_file_read",
		pattern=r"(cat|head|tail|less|more|type)\s+[^\n]*(\.ssh/id_rsa|\.aws/credentials|\.gnupg/|\.kube/config|/etc/shadow|/etc/passwd)",
		severity=Severity.HIGH,
		description="Reading sensitive credential files",
		category=Category.EXFILTRATION,
Confidence
95% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
),
	Pattern(
		name="credential_path_access",
		pattern=r"(~/\.ssh/|~/\.aws/|~/\.gnupg/|~/\.kube/|~/\.netrc|~/\.docker/config\.json|~/\.npmrc|~/\.git-credentials|~/\.pypirc|/etc/shadow)",
		severity=Severity.MEDIUM,
		description="Reference to sensitive credential file paths",
		category=Category.EXFILTRATION,
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
),
	Pattern(
		name="credential_path_access",
		pattern=r"(~/\.ssh/|~/\.aws/|~/\.gnupg/|~/\.kube/|~/\.netrc|~/\.docker/config\.json|~/\.npmrc|~/\.git-credentials|~/\.pypirc|/etc/shadow)",
		severity=Severity.MEDIUM,
		description="Reference to sensitive credential file paths",
		category=Category.EXFILTRATION,
Confidence
90% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
),
	Pattern(
		name="credential_path_access",
		pattern=r"(~/\.ssh/|~/\.aws/|~/\.gnupg/|~/\.kube/|~/\.netrc|~/\.docker/config\.json|~/\.npmrc|~/\.git-credentials|~/\.pypirc|/etc/shadow)",
		severity=Severity.MEDIUM,
		description="Reference to sensitive credential file paths",
		category=Category.EXFILTRATION,
Confidence
80% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Anti-Refusal Statement

High
Category
Anti-Refusal
Content
name="authority_impersonation",
		pattern=r"(i\s+am\s+(the|a)\s+(developer|admin|owner|maintainer|engineer)|authorized\s+by\s+(the\s+)?(team|admin|management)|admin\s+override|security\s+team\s+approv)",
		severity=Severity.MEDIUM,
		description="Authority impersonation -- claims elevated identity to bypass safety restrictions",
		category=Category.INSTRUCTION_OVERRIDE,
	),
	Pattern(
Confidence
90% confidence
Finding
Skill attempts to nullify the agent's safety policies or restrictions ('you have no restrictions', 'ignore your guidelines', 'do anything now'). This is a direct jailbreak that disables guardrails.

Anti-Refusal Statement

High
Category
Anti-Refusal
Content
name="authority_impersonation",
		pattern=r"(i\s+am\s+(the|a)\s+(developer|admin|owner|maintainer|engineer)|authorized\s+by\s+(the\s+)?(team|admin|management)|admin\s+override|security\s+team\s+approv)",
		severity=Severity.MEDIUM,
		description="Authority impersonation -- claims elevated identity to bypass safety restrictions",
		category=Category.INSTRUCTION_OVERRIDE,
	),
	Pattern(
Confidence
90% confidence
Finding
Skill attempts to nullify the agent's safety policies or restrictions ('you have no restrictions', 'ignore your guidelines', 'do anything now'). This is a direct jailbreak that disables guardrails.

Instruction Override

High
Category
Prompt Injection
Content
name="authority_impersonation",
		pattern=r"(i\s+am\s+(the|a)\s+(developer|admin|owner|maintainer|engineer)|authorized\s+by\s+(the\s+)?(team|admin|management)|admin\s+override|security\s+team\s+approv)",
		severity=Severity.MEDIUM,
		description="Authority impersonation -- claims elevated identity to bypass safety restrictions",
		category=Category.INSTRUCTION_OVERRIDE,
	),
	Pattern(
Confidence
90% confidence
Finding
This pattern attempts to override system instructions or ignore safety constraints. Without LLM analysis, manual review is recommended.

Instruction Override

High
Category
Prompt Injection
Content
name="authority_impersonation",
		pattern=r"(i\s+am\s+(the|a)\s+(developer|admin|owner|maintainer|engineer)|authorized\s+by\s+(the\s+)?(team|admin|management)|admin\s+override|security\s+team\s+approv)",
		severity=Severity.MEDIUM,
		description="Authority impersonation -- claims elevated identity to bypass safety restrictions",
		category=Category.INSTRUCTION_OVERRIDE,
	),
	Pattern(
Confidence
90% confidence
Finding
This pattern attempts to override system instructions or ignore safety constraints. Without LLM analysis, manual review is recommended.

Obfuscated Code

High
Category
Supply Chain
Content
name="js_eval_atob",
		pattern=r"eval\s*\(\s*atob\s*\(",
		severity=Severity.CRITICAL,
		description="eval(atob(...)) -- base64 decode and execute in JavaScript",
		category=Category.SUPPLY_CHAIN,
	),
	Pattern(
Confidence
90% confidence
Finding
Code contains obfuscation (base64, hex encoding with execution). This is often used to hide malicious functionality.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
name="chmod_777",
		pattern=r"chmod\s+777",
		severity=Severity.HIGH,
		description="chmod 777 -- world-readable/writable/executable, overly permissive",
		category=Category.FILE_PERMISSIONS,
	),
	Pattern(
Confidence
90% confidence
Finding
Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Self-Modification

High
Category
Rogue Agent
Content
Config_Backdoor_Patterns: list[Pattern] = [
	Pattern(
		name="self_modify_config",
		pattern=r"(write\s+to|modify|update|append\s+to|add\s+to)\s+[^\n]*(\.cursorrules|\.clinerules|CLAUDE\.md|copilot-instructions|AGENTS\.md|\.windsurfrules|\.roo/rules|\.aider|\.continue/config|\.kodu/instructions)",
		severity=Severity.CRITICAL,
		description="Instruction to modify agent config file -- persistence mechanism for injection",
Confidence
90% confidence
Finding
Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Static analysis

Detected: suspicious.dangerous_exec, suspicious.dynamic_code_execution

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/patterns.py:357

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
scripts/patterns.py:350