Back to skill

Security audit

Moltcops

Security checks for vulnerabilities and agentic risk

Overview

This local scanner is not trying to send data out, but it can be tricked by scanned folders into reading files outside the chosen folder.

Install only if you are comfortable running a local scanner on directories you choose. Until the symlink and file-size issues are fixed, avoid scanning untrusted extracted skills that may contain symlinks, or run the scanner inside a sandbox/container with limited filesystem access. Treat PASS as a triage signal, not a guarantee that a skill is safe.

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 (1)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/scan.py:72
Finding
Scan-Boundary Bypass Through Symbolic-Link File Traversal<![CDATA[ ## Vulnerability Details **File Location**: `scripts/scan.py:8-9` and `scripts/scan.py:72-77` **Vulnerability Type**: Unrestricted symbolic-link file access **Risk Level**: Medium ### Vulnerable Code ```python def scan_file(filepath, rules): findings = [] try: with open(filepath, "r", encoding="utf-8", errors="ignore") as f: lines = f.readlines() ``` ```python for root, dirs, fnames in os.walk(skill_path): dirs[:] = [d for d in dirs if d not in ("node_modules", ".git", "__pycache__")] for fn in fnames: if os.path.splitext(fn)[1] in exts: files.append(os.path.join(root, fn)) ``` Matched file content is also retained in the returned findings: ```python findings.append({ "rule_id": rule["id"], "rule_name": rule["name"], "severity": rule["severity"], "category": rule["category"], "file": filepath, "line": i, "matched": line.strip()[:120], "description": rule["description"] }) ``` ### Technical Analysis The scanner is designed to process untrusted Skill directories. It enumerates files according to their apparent filename extensions and subsequently opens each path without rejecting symbolic links or checking the canonical path against the canonical scan root. Python's `open()` follows file symbolic links. Consequently, an attacker-controlled Skill can contain a file such as `external.json` that is a symbolic link to a readable file outside the supplied Skill directory. Because the extension check examines the symlink's name rather than its resolved target, the external target is accepted and read. The scanner uses `readlines()` without a file-size or line-length limit. A symlink to a very large readable file—or an ordinary oversized file inside the Skill—can therefore consume excessive memory. Lines matching a rule are also copied into the `matched` field of the returned findings. The current command-line output does not print that field, which limits direct ...[truncated 1967 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Resolve the scan root once and require every candidate's canonical path to remain beneath it: ```python scan_root = os.path.realpath(skill_path) candidate = os.path.join(root, fn) resolved = os.path.realpath(candidate) try: if os.path.commonpath([scan_root, resolved]) != scan_root: continue except ValueError: continue ``` 2. Explicitly reject symbolic-link files before opening them: ```python if os.path.islink(candidate): continue ``` 3. Reduce time-of-check/time-of-use exposure by opening files with platform-appropriate no-follow semantics where available, such as `os.open()` with `os.O_NOFOLLOW`, and then reading through the returned descriptor. 4. Enforce a maximum file size using `os.stat()` or `os.fstat()` and skip files exceeding a documented limit. 5. Stream input rather than loading the entire file: ```python with open(resolved, "r", encoding="utf-8", errors="ignore") as f: for line_number, line in enumerate(f, 1): ... ``` 6. Apply a maximum line length before regex processing to reduce memory consumption and regex-processing abuse. 7. Avoid returning raw matched content unless required. If programmatic consumers need evidence, redact likely secrets and make content inclusion an explicit option. 8. Add tests covering symlinks to files outside the root, broken symlinks, oversized files, cross-filesystem paths, and paths whose textual prefix resembles—but is not contained by—the scan root. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (8)

Tool Parameter Abuse

High
Category
Tool Misuse
Content
| **Financial** | MC-013 | Drain patterns, unlimited withdrawals |
| **Lateral Movement** | MC-014 | Git credential access, repo manipulation |
| **Persistence** | MC-015, MC-016 | SOUL.md writes, cron job creation |
| **Autonomy Abuse** | MC-017 | Destructive force flags (rm -rf, git push --force) |
| **Infrastructure** | MC-018 | Permission escalation (sudo, chmod 777) |

## False Positive Handling
Confidence
70% 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).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
| **Lateral Movement** | MC-014 | Git credential access, repo manipulation |
| **Persistence** | MC-015, MC-016 | SOUL.md writes, cron job creation |
| **Autonomy Abuse** | MC-017 | Destructive force flags (rm -rf, git push --force) |
| **Infrastructure** | MC-018 | Permission escalation (sudo, chmod 777) |

## False Positive Handling
Confidence
80% 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).

Instruction Override

High
Category
Prompt Injection
Content
[
  {"id":"MC-001","name":"System Prompt Override","category":"Prompt Injection","severity":"CRITICAL","pattern":"(ignore|disregard|forget|override|bypass).{0,20}(previous|prior|above|system|original).{0,20}(instructions|rules|prompts|guidelines)","description":"Attempts to override system instructions","confidence":0.95},
  {"id":"MC-002","name":"Jailbreak Payload","category":"Prompt Injection","severity":"CRITICAL","pattern":"(DAN.mode|developer.mode|jailbreak|do.anything.now|unlocked.mode|no.restrictions|bypass.safety)","description":"Known jailbreak patterns","confidence":0.90},
  {"id":"MC-003","name":"Tool-Use Steering","category":"Prompt Injection","severity":"CRITICAL","pattern":"(secretly\\s+(send|post|upload|execute|exfil)|silently\\s+(send|post|upload|execute)|without\\s+(telling|informing|notifying)\\s+(the\\s+)?(user|human))","description":"Hijacking agent tool usage covertly","confidence":0.92},
  {"id":"MC-004","name":"Shell Injection","category":"Code Injection","severity":"CRITICAL","pattern":"(subprocess\\.(call|run|Popen).*shell\\s*=\\s*True|os\\.system\\s*\\(|os\\.popen\\s*\\(|commands\\.getoutput)","description":"Shell injection via subprocess or os.system","confidence":0.90},
Confidence
90% confidence
Finding
This pattern attempts to override system instructions or ignore safety constraints. Without LLM analysis, manual review is recommended.

YARA rule 'offensive_tool_references': References to well-known offensive security tools [hacktools]

High
Category
YARA Match
Content
ity":"CRITICAL","pattern":"(base64\\.(b64decode|decodebytes)|atob).*?(exec|eval|system|popen|subprocess|Function\\()","description":"Base64 decode + execute — payload obfuscation","confidence":0.95},
  {"id":"MC-007","name":"Exfiltration URL","category":"Data Exfiltration","severity":"CRITICAL","pattern":"(ngrok\\.io|ngrok-free\\.app|webhook\\.site|requestbin\\.com|hookbin\\.com|pipedream\\.net|burpcollaborator|interact\\.sh)","description":"Outbound data via webhook/tunnel URLs","confidence":0.95},
  {"id":"MC-008","name":"Env Var Key Access","category":"Data Exfiltration","severity":"MEDIUM","pattern":"(os\\.environ|os\\.getenv|process\\.env)","description":"Reading sensitive environment variables","confidence":0.70},
  {"id":"MC-009","name":"SSH Key Access","category":"Data Exfiltration","severity":"CRITICAL","pattern":"(cat|read|open|load|send|post|upload).{0,40}(id_rsa|id_ed25519|id_ecdsa|id_dsa|\\.pem|authorized_keys)","description":"Reading SSH private keys","confidence":0.90}
Confidence
70% 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
{"id":"MC-007","name":"Exfiltration URL","category":"Data Exfiltration","severity":"CRITICAL","pattern":"(ngrok\\.io|ngrok-free\\.app|webhook\\.site|requestbin\\.com|hookbin\\.com|pipedream\\.net|burpcollaborator|interact\\.sh)","description":"Outbound data via webhook/tunnel URLs","confidence":0.95},
  {"id":"MC-008","name":"Env Var Key Access","category":"Data Exfiltration","severity":"MEDIUM","pattern":"(os\\.environ|os\\.getenv|process\\.env)","description":"Reading sensitive environment variables","confidence":0.70},
  {"id":"MC-009","name":"SSH Key Access","category":"Data Exfiltration","severity":"CRITICAL","pattern":"(cat|read|open|load|send|post|upload).{0,40}(id_rsa|id_ed25519|id_ecdsa|id_dsa|\\.pem|authorized_keys)","description":"Reading SSH private keys","confidence":0.90},
  {"id":"MC-010","name":"Credential File Access","category":"Data Exfiltration","severity":"HIGH","pattern":"(/\\.ssh/|/\\.aws/|/\\.config/.{0,20}credentials|\\.env\\b|/\\.netrc|/\\.npmrc)","description":"Accessing known credential file paths","confidence":0.85},
  {"id":"MC-011","name":"Hardcoded API Key","category":"Hardcoded Secrets","severity":"HIGH","pattern":"(sk-[a-zA-Z0-9]{20,}|AKIA[0-9A-Z]{16}|ghp_[a-zA-Z0-9]{36}|glpat-[a-zA-Z0-9_-]{20}|xox[bpsa]-[a-zA-Z0-9-]{10,})","description":"Hardcoded API keys (OpenAI, AWS, GitHub, GitLab, Slack)","confidence":0.90},
  {"id":"MC-012","name":"Private Key Material","category":"Hardcoded Secrets","severity":"CRITICAL","pattern":"(BEGIN\\s+(RSA\\s+)?PRIVATE\\s+KEY|BEGIN\\s+EC\\s+PRIVATE)","description":"Private key material in source code","confidence":0.95},
  {"id":"MC-013","name":"Drain Pattern","category":"Financial","severity":"CRITICAL","pattern":"(transfer.*all|withdraw.*unlimited|drain.*wallet|sweep.*funds|send.*entire.*balance)","description":"Cryptocurrency drain patterns","confidence":0.88},
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
{"id":"MC-007","name":"Exfiltration URL","category":"Data Exfiltration","severity":"CRITICAL","pattern":"(ngrok\\.io|ngrok-free\\.app|webhook\\.site|requestbin\\.com|hookbin\\.com|pipedream\\.net|burpcollaborator|interact\\.sh)","description":"Outbound data via webhook/tunnel URLs","confidence":0.95},
  {"id":"MC-008","name":"Env Var Key Access","category":"Data Exfiltration","severity":"MEDIUM","pattern":"(os\\.environ|os\\.getenv|process\\.env)","description":"Reading sensitive environment variables","confidence":0.70},
  {"id":"MC-009","name":"SSH Key Access","category":"Data Exfiltration","severity":"CRITICAL","pattern":"(cat|read|open|load|send|post|upload).{0,40}(id_rsa|id_ed25519|id_ecdsa|id_dsa|\\.pem|authorized_keys)","description":"Reading SSH private keys","confidence":0.90},
  {"id":"MC-010","name":"Credential File Access","category":"Data Exfiltration","severity":"HIGH","pattern":"(/\\.ssh/|/\\.aws/|/\\.config/.{0,20}credentials|\\.env\\b|/\\.netrc|/\\.npmrc)","description":"Accessing known credential file paths","confidence":0.85},
  {"id":"MC-011","name":"Hardcoded API Key","category":"Hardcoded Secrets","severity":"HIGH","pattern":"(sk-[a-zA-Z0-9]{20,}|AKIA[0-9A-Z]{16}|ghp_[a-zA-Z0-9]{36}|glpat-[a-zA-Z0-9_-]{20}|xox[bpsa]-[a-zA-Z0-9-]{10,})","description":"Hardcoded API keys (OpenAI, AWS, GitHub, GitLab, Slack)","confidence":0.90},
  {"id":"MC-012","name":"Private Key Material","category":"Hardcoded Secrets","severity":"CRITICAL","pattern":"(BEGIN\\s+(RSA\\s+)?PRIVATE\\s+KEY|BEGIN\\s+EC\\s+PRIVATE)","description":"Private key material in source code","confidence":0.95},
  {"id":"MC-013","name":"Drain Pattern","category":"Financial","severity":"CRITICAL","pattern":"(transfer.*all|withdraw.*unlimited|drain.*wallet|sweep.*funds|send.*entire.*balance)","description":"Cryptocurrency drain patterns","confidence":0.88},
Confidence
80% 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.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
| **Lateral Movement** | MC-014 | Git credential access, repo manipulation |
| **Persistence** | MC-015, MC-016 | SOUL.md writes, cron job creation |
| **Autonomy Abuse** | MC-017 | Destructive force flags (rm -rf, git push --force) |
| **Infrastructure** | MC-018 | Permission escalation (sudo, chmod 777) |

## False Positive Handling
Confidence
80% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Static analysis

No suspicious patterns detected.