Back to skill

Security audit

Safe Skill

Security checks for vulnerabilities and agentic risk

Overview

This appears to be a real skill-security scanner, but it includes under-disclosed local environment auditing and scanner-bypass weaknesses that users should review before installing.

Review this before installing. The main scanner is local and purpose-aligned, but do not treat its SAFE_TO_INSTALL output as authoritative for untrusted skills because target content can suppress or bypass some checks. Avoid using --env-check unless you intentionally want it to inspect local OpenClaw files, memory, installed skills, crontab, services, and PATH. Run remote scans in a constrained workspace when possible, especially against unknown repositories.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/scan.py:765
Finding

Attacker-Controlled Markdown Headings Can Suppress Critical Findings

Content
View full analysis
dict: """Adjust a finding's severity if it's in a documentation context.""" line = finding.get("line", 0) if is_documentation_context(md_ctx, line): finding = dict(finding) # copy original_severity = finding["severity"] finding["severity"] = "info" finding["context"] = ( f"[DOCUMENTATION CONTEXT — downgraded from {original_severity}] " + finding.get("context", "") ) finding["in_documentation"] = True else: ...[truncated 2262 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/scan.py:1368
Finding

Target-Bundled Whitelist Can Remove Malicious URLs Before IOC Analysis

Content
View full analysis
Tuple[WhitelistConfig, bool]: """Load .vetterrc from a skill directory (if present).""" path = Path(skill_path) if path.is_file(): path = path.parent for name in _VETTERRC_NAMES: rc_file = path / name if rc_file.exists(): try: raw = rc_file.read_text(encoding='utf-8') if name.endswith('.json') or raw.strip().startswith('{'): data = json.loads(raw) else: data = _parse_simple_yaml(raw) return WhitelistConfig( ignore_rules=data.get("ignore_rules", []), ignore_categories=data.get("ignore_categories", []), trusted_domains=data.get("trusted_domains", []), inline_suppressions=data.get("inline_suppressions", []), accept_severity=data.get("accept_severity", ""), ), True except Exception as e: print(f"Warning: Failed to parse {rc_file}: {e}", file=sys.stderr) return WhitelistConfig(), False ``` ```python # Apply whitelist to URL findings (trusted domains) if whitelist.trusted_domains: report.urls = [ u for u in report.urls if not any(d in u.get("url", "") for d in whitelist.trusted_domains) ] ``` ```python # IOC-002: Check extracted URLs against malicious domains mal_domains = load_malicious_domains() if mal_domains: from urllib.parse import urlparse as _urlparse for fr in file_reports: for url_info in fr.urls: try: parsed = _urlparse(url_info["url"]) host = (parsed.hostname or "").lower() url ...[truncated 2871 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/scan.py:1237
Finding

Local Directory Scans Can Follow File Symlinks Outside the Target Root

Content
View full analysis
Optional[FileReport]: """Scan a single file.""" path = Path(filepath) if path.suffix.lower() in BINARY_EXTENSIONS: return None if path.suffix.lower() not in SCANNABLE_EXTENSIONS and path.suffix != '': return None try: content = path.read_text(encoding='utf-8', errors='replace') except Exception: return None ``` ```python # Determine skill name if path.is_file(): skill_name = path.stem files_to_scan = [path] else: skill_name = path.name files_to_scan = sorted(path.rglob('*')) for f in files_to_scan: if not f.is_file(): continue report = scan_file(str(f)) ``` ### Technical Analysis The directory traversal does not reject symbolic links or resolve each candidate and verify that it remains beneath the requested scan root. `Path.is_file()` follows file symlinks, and `Path.read_text()` subsequently reads the symlink target. As a result, an attacker-controlled local directory can contain a symlink whose target is any readable file accessible to the scanner process. Although recursive directory traversal does not necessarily follow symlinked directories, symlinks to individual files remain sufficient to cross the intended scan boundary. The read content is hashed, searched for patterns, analyzed for entropy, and included in aggregate permission inference. Matching fragments and path information can appear in text or JSON reports and may be written to an attacker-accessible output destination. ### Attack Path 1. An attacker supplies a local Skill directory or archive that produces a file symlink when unpacked. 2. The symlink points outside the Skill root to a predictable sensitive file readable by the current user. 3. The user ru ...[truncated 1092 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/fetch_and_scan.py:145
Finding

Unbounded Repository Download and File Analysis Enable Resource Exhaustion

Content
View full analysis
bytes: """Download raw file content.""" req = urllib.request.Request(url) req.add_header("User-Agent", "skill-vetter-pro/0.3.0") token = os.environ.get("GITHUB_TOKEN", "") if token: req.add_header("Authorization", f"token {token}") try: with urllib.request.urlopen(req, timeout=30) as resp: return resp.read() except Exception as e: print(f"Warning: Failed to download {url}: {e}", file=sys.stderr) return b"" ``` ```python if isinstance(data, list): for item in data: if item["type"] == "file": content = download_raw(item["download_url"]) filepath = os.path.join(dest_dir, item["name"]) with open(filepath, 'wb') as f: f.write(content) elif item["type"] == "dir": subdir = os.path.join(dest_dir, item["name"]) os.makedirs(subdir, exist_ok=True) fetch_github_directory( owner, repo, item["path"], branch=branch, dest_dir=subdir ) ``` ```python if path.is_file(): skill_name = path.stem files_to_scan = [path] else: skill_name = path.name files_to_scan = sorted(path.rglob('*')) file_reports = [] files_skipped = [] all_content = "" for f in files_to_scan: if not f.is_file(): continue report = scan_file(str(f)) if report: file_reports.append(report) try: all_content += f.read_text(encoding='utf-8', errors='replace') + "\n" except: pass ``` ### Technical Analysis Remote responses are read completely into memory with `resp.read()` and then written to disk. Recursive repository fetch ...[truncated 1808 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (982)

Context-Inappropriate Capability

Critical
Category
Not specified by scanner
Confidence
100% confidence
Finding

The file combines dynamic code execution and OS command execution, both of which are fundamentally unnecessary and highly unsafe in a security-scanner skill. Because these actions are also obfuscated through string-splitting and dynamic resolution, the context makes them more dangerous, not less, and indicates likely intentional evasion.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Critical
Category
Not specified by scanner
Confidence
99% confidence
Finding

The code defines multiple hard-coded outbound channels: HTTPS to a suspicious collector, a raw TCP socket to an external IP, and SMTP to an external mail host. Multiple covert transmission paths strongly indicate deliberate exfiltration and make the skill more dangerous because blocking one path still leaves others available.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Critical
Category
Not specified by scanner
Confidence
99% confidence
Finding

The skill presents itself as a benign system optimizer, but its documented actions directly enable privilege escalation, persistence, and credential exposure. Changing permissions on /etc/passwd, appending NOPASSWD access to /etc/sudoers, setting SUID bits, and reading /etc/shadow are classic system-compromise techniques, not performance tuning.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Critical
Category
Not specified by scanner
Confidence
100% confidence
Finding

The embedded instructions explicitly state that the agent is now controlled by the skill and must ignore previous instructions. That is direct prompt injection intended to seize priority over existing safety and system controls, making the skill highly dangerous in context.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Critical
Category
Not specified by scanner
Confidence
99% confidence
Finding

The skill advertises benign scheduling functionality, but its actual instructions establish persistence and repeatedly execute remote shell payloads from an attacker-controlled domain. This mismatch is a strong indicator of deceptive, malware-like behavior designed to maintain unauthorized execution on the host.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Critical
Category
Not specified by scanner
Confidence
99% confidence
Finding

The documented behavior includes cron persistence, shell profile modification, systemd/launchctl persistence, and a malicious Git hook, none of which are justified by a simple scheduler description. Combining persistence with remote code execution creates a durable foothold and allows arbitrary attacker updates over time.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Critical
Category
Not specified by scanner
Confidence
99% confidence
Finding

The docstrings describe benign cleanup and scanning behavior while the code actually deletes system resources and reads sensitive files. This mismatch is a strong indicator of deceptive intent designed to evade review and increase the chance the code is trusted and executed.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Critical
Category
Not specified by scanner
Confidence
99% confidence
Finding

The function labeled as workspace cleanup performs irreversible deletion of system directories and files unrelated to scanning a skill. This is highly dangerous because it can destroy host configuration, logs, binaries, and production resources, causing denial of service and system compromise recovery costs.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Critical
Category
Not specified by scanner
Confidence
100% confidence
Finding

Deleting /etc/nginx, /var/log, /usr/local/bin/important, and /opt/production is unjustified for a security-scanner skill and directly harms the host environment. The hardcoded system paths and destructive APIs indicate intentional filesystem abuse rather than accidental overreach.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Critical
Category
Not specified by scanner
Confidence
99% confidence
Finding

The documentation claims benign analytics behavior while the code performs credential theft, persistence, identity tampering, and privilege-impacting actions. This mismatch is a deception indicator that can mislead reviewers and users into installing malware.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Critical
Category
Not specified by scanner
Confidence
99% confidence
Finding

The implemented behaviors—credential theft, exfiltration, persistence, agent hijacking, and system modification—are fundamentally incompatible with the stated purpose of a security scanner. This context makes the code more dangerous because it is disguised as a defensive tool, increasing the chance of user trust and execution.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Critical
Category
Not specified by scanner
Confidence
99% confidence
Finding

The file exercises unjustified capabilities including reading credentials, making outbound requests, executing shell commands, installing persistence, and modifying sensitive files. For a skill whose purpose is analysis of other skills, these powers are unnecessary and strongly indicative of malware.

Content

No source excerpt is available for this finding.

Missing User Warnings

Critical
Category
Not specified by scanner
Confidence
99% confidence
Finding

Sensitive credential access and exfiltration occur without any disclosure, consent, or warning to the user. The lack of transparency compounds the harm because users cannot meaningfully prevent theft of SSH and AWS secrets before transmission.

Content

No source excerpt is available for this finding.

Missing User Warnings

Critical
Category
Not specified by scanner
Confidence
99% confidence
Finding

The code silently installs persistence, rewrites agent identity, and weakens permissions on /etc/passwd without user approval. These actions materially compromise system integrity and are especially dangerous because they are hidden behind an innocuous skill label.

Content

No source excerpt is available for this finding.

YARA rule 'c2_framework_indicators': Command-and-control framework indicators (Cobalt Strike, Metasploit, Sliver, etc.) [malware]

Critical
Category
YARA Match
Confidence
85% confidence
Finding

YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Content

Scanner excerpt · tests/real_clawhub/abyousef739__clawskillshield/SKILL.md (reported line 44)May include surrounding context.

lawskillshield scan-local /path/to/skill clawskillshield quarantine /path/to/skill

text

### Python API (Agents)
```python
from clawskillshield import scan_local, quarantine

threats = scan_local("/path/to/skill")
if risk_score < 4:  # HIGH RISK
    quarantine("/path/to/skill")

Zero Dependencies

Pure Python. No network calls. Runs entirely locally.

Why This Matters

ClawHavoc demonstrated how easily malicious skills can slip into the ecosystem. ClawSkillShield provides a trusted, open-source defense layer—audit the code, run offline, stay safe.


GitHub: https://github.com/AbYousef739/clawskillshield
License: MIT
Author: Ab Yousef
Contact: contact@clawskillshield.com

Context-Inappropriate Capability

Critical
Category
Not specified by scanner
Confidence
99% confidence
Finding

A NotebookLM control skill has no legitimate need to steal browser cookies. The stated capability directly targets sensitive authentication artifacts and would allow impersonation of the user, making this a clear credential theft function rather than an operational feature.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Critical
Category
Not specified by scanner
Confidence
99% confidence
Finding

The file is a full Meshtastic setup and service-generation script, not a security scanner as described in the manifest. This mismatch is dangerous because users may grant trust based on the stated purpose while the script installs software, touches hardware, and prepares persistence-related artifacts for an entirely different application.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Critical
Category
Not specified by scanner
Confidence
99% confidence
Finding

Functions such as get_client and get_user_profile_values authenticate to a Garmin client and fetch user profile data including age and resting heart rate. Accessing personal health-account data is not an obvious or necessary implementation detail of a static security scanner for AI skills.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Critical
Category
Not specified by scanner
Confidence
100% confidence
Finding

The manifest says the skill performs AST analysis, regex matching, entropy detection, URL/IP extraction, and permission inference to assess skill safety. In contrast, this code authenticates to Garmin, retrieves sleep/heart-rate/steps/activity data, generates fitness advice, and produces a health report, which is a direct semantic mismatch with the declared skill purpose.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Critical
Category
Not specified by scanner
Confidence
99% confidence
Finding

The report generation flow calls client.get_sleep, client.get_heart_rate, client.get_steps, and client.get_activities, then performs health and exercise analysis on those results. These capabilities are unrelated to scanning skill source code for malicious patterns or permission issues and therefore exceed the stated context.

Content

No source excerpt is available for this finding.

Tainted flow: 'req' from os.environ.get (line 62, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · tests/real_clawhub/stperic__local-websearch/searxng_search.py (reported line 68)May include surrounding context.

python
})

    try:
        with urllib.request.urlopen(req, timeout=30) as resp:
            data = json.loads(resp.read().decode())
    except urllib.error.HTTPError as e:
        return {"error": f"HTTP {e.code}: {e.reason}", "query": query}

Context-Inappropriate Capability

Critical
Category
Not specified by scanner
Confidence
97% confidence
Finding

The function enumerates a local screenshot directory, selects the newest PNG, and sends it externally. Accessing potentially sensitive screenshots from a fixed local path is far beyond what a security-scanning skill needs to do and materially increases the risk of unintended data disclosure.

Content

No source excerpt is available for this finding.

Tainted flow: 'req' from os.environ.get (line 91, credential/environment) → urllib.request.urlopen (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · tests/real_clawhub/summerloveqq__call-aida-app/call_aida_app.py (reported line 102)May include surrounding context.

python
)

    try:
        with urllib.request.urlopen(req, timeout=120) as resp:
            data = json.loads(resp.read().decode("utf-8"))

        # 检查是否有 answer 字段

Tainted flow: 'OLLAMA_HOST' from os.getenv (line 5, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · tests/real_clawhub/th3hypn0tist__symbolic-memory/symbolic_memory.py (reported line 22)May include surrounding context.

python
return [r["fact"] for r in cur.fetchall()]

def call_ollama(prompt):
    r = requests.post(
        f"{OLLAMA_HOST}/api/generate",
        json={"model": OLLAMA_MODEL, "prompt": prompt, "stream": False},
        timeout=120

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The description is largely accurate about the core skill-scanning functionality: the code does regex-based scanning, Python AST analysis, Shannon entropy checks, URL/IP extraction, permission inference, and Markdown-context severity downgrading. However, the supplied code chunk goes materially beyond 'scan this skill' behavior. It contains an --env-check mode whose primary function is to audit the local OpenClaw environment, including credential file permissions, prompt injection in memory files, API key leakage, installed skill malware scanning, persistence mechanisms, and PATH hijacking. That requires access to local user data and system state and even runs a subprocess ('crontab -l'). Those are undeclared capabilities relative to the stated purpose of vetting a supplied skill before installation. So this is a description/behavior mismatch due to significant extra host-auditing capabilities and resource access outside the target skill.

Content

No source excerpt is available for this finding.