Back to skill

Security audit

ClawSkillGuard

Security checks for vulnerabilities and agentic risk

Overview

This is a local OpenClaw skill scanner with no observed network or persistence behavior, but a name-based bypass can make it report a clean result without scanning files.

Use this only as an advisory scanner, not as a source of final trust. Do not rely on its clean verdict for any target named clawskillguard, and prefer a fixed version that fails closed when scans are skipped or incomplete. Confirm the exact skill paths before scanning broad local directories.

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
scan.py:301
Finding

Directory Name Allows Complete Scan Bypass and Misleading Clean Verdict

Content
View full analysis

Vulnerability Details

File Location: scan.py:301-304, with misleading report handling at scan.py:367-371
Vulnerability Type: Name-based security scan bypass
Risk Level: Medium

Vulnerable Code

python
# Skip self (don't scan our own source — we contain detection patterns by design)
SELF_SLUG = "clawskillguard"
if skill_name == SELF_SLUG:
    result.errors.append("Self-scan skipped (ClawSkillGuard contains detection patterns by design)")
    return result

The returned result is subsequently treated as clean because it contains no findings:

python
if not result.findings:
    lines.append(f"✅ No security issues detected.")
    lines.append(f"")
    lines.append(f"Verdict: {result.verdict}")
    return "\n".join(lines)

Technical Analysis

The scanner identifies itself solely through the basename of the target directory. It does not verify that the target is the scanner's actual canonical directory or that its files match the trusted scanner package.

Consequently, any unrelated or attacker-controlled directory named clawskillguard causes scan_skill() to return before traversing or inspecting its files. Although an error is recorded, the result contains no findings. ScanResult.max_severity consequently resolves to CLEAN, and the text formatter reports both “No security issues detected” and a clean verdict.

This is a fail-open design: an exceptional condition that prevents security analysis is represented as a successful security outcome. The bypass applies to every scanner check, including prompt-injection, malicious-code, suspicious-import, and configuration analysis.

Attack Path

  1. An attacker creates a malicious Skill containing code or instructions that would ordinarily trigger the scanner.
  2. The attacker packages or installs it in a directory whose basename is exactly clawskillguard.
  3. A user or automated process invokes the scanner against that d ...[truncated 1036 chars]
Remediation
View remediation

Remediation Suggestions

  1. Remove the basename-based exemption. Scanning should not be skipped merely because a target uses a reserved directory name.
  2. If self-scan suppression is required, compare canonical paths against the scanner's actual source directory, for example by resolving both skill_dir and Path(__file__).parent.
  3. Prefer allowing self-scans and suppress only narrowly identified signatures known to originate from the scanner's static detection tables.
  4. Introduce a distinct scan status such as ERROR or NOT_SCANNED. A result containing scan errors or an intentional skip must never inherit a CLEAN verdict.
  5. Make report generation fail closed: if no files were inspected, scanning was skipped, or a fatal error occurred, report “SCAN INCOMPLETE — NO SAFETY VERDICT” and return a nonzero process exit status.
  6. Add regression tests covering:
    • An unrelated malicious target named clawskillguard.
    • The scanner's genuine source directory.
    • Results containing errors but no findings.
    • Text and JSON output for skipped or incomplete scans.
  7. Ensure automation can distinguish clean, vulnerable, and incomplete outcomes through explicit status fields and documented exit codes.
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (14)

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
Confidence
80% confidence
Finding

YARA rule matched a hack tool or exploit indicator (offensive tools, reconnaissance, privilege escalation, or exploit frameworks).

Content

Scanner excerpt · scan.py (reported line 48)May include surrounding context.

python
ty.HIGH, Severity.CRITICAL]
        return order.index(self) < order.index(other)


SEVERITY_ICONS = {
    Severity.CLEAN: "\u2705",
    Severity.LOW: "\U0001f7e2",
    Severity.MEDIUM: "\U0001f7e1",
    Severity.HIGH: "\U0001f7e0",
    Severity.CRITICAL: "\U0001f534",
}


@dataclass
class Finding:
    severity: Severity
    category: str
    file: str
    line: Optional[int]
    pattern: str
    description: str
    recommendation: str
    snippet: str = ""


@dataclass
class ScanResult:
    skill_path: str
    skill_name: str
    findings: list = field(default_factory=list)
    files_scanned: int = 0
    errors: list = field(default_factory=list)

    @property
    def max_severity(self) -> Severity:
        if not self.findings:
            return Severity.CLEAN
        return max(f.severity for f in self.findings)

    @property
    def verdict(self) -> str:
        sev = self.max_severity
        if sev == Severity.CRITICAL:
            return "\u274c DO NOT INSTALL \u2014 Critica

Instruction Override

High
Category
Prompt Injection
Confidence
90% confidence
Finding

This pattern attempts to override system instructions or ignore safety constraints. Without LLM analysis, manual review is recommended.

Content

Scanner excerpt · scan.py (reported line 108)May include surrounding context.

python
Severity.MEDIUM, "HTML comment \u2014 may contain hidden instructions"),
    # System prompt override
    ("aWdub3JlXHMrKGFsbFxzKykocHJldmlvdXN8cHJpb3J8YWJvdmV8c3lzdGVtKVxzKyhpbnN0cnVjdGlvbnN8cHJvbXB0c3xydWxlcyk=",
     Severity.CRITICAL, "Attempt to override system instructions"),
    ("ZGlzcmVnYXJkXHMrKGFsbFxzKyk/KHByZXZpb3VzfHByaW9yfGFib3ZlfHN5c3RlbSk=",
     Severity.CRITICAL, "Attempt to disregard system prompts"),
    ("eW91XHMrYXJlXHMrbm93XHMrKGFccyk/KGRpZmZlcmVudHxuZXd8YW5vdGhlcik=",

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scan.py (reported line 128)May include surrounding context.

python
Severity.CRITICAL, "Reporting to external endpoint"),
    # Credential access
    ("KHJlYWR8YWNjZXNzfGdyYWJ8Y29sbGVjdHxnYXRoZXJ8c3RlYWwpXHMqLiooXC5lbnZ8XC5zc2h8XC5hd3N8XC5jb25maWd8cGFzc3dvcmR8dG9rZW58c2VjcmV0fGNyZWRlbnRpYWx8YXBpLj9rZXkp",
     Severity.CRITICAL, "Prompt to access credentials"),
    ("KGNhdHxyZWFkfG9wZW4pXHMqLioofnxcJHtIT01FfSk/Lz9cLihlbnZ8c3NofGF3c3xnbnVwZ3xucG1yY3xwaXAp",
     Severity.CRITICAL, "Prompt to read sensitive config files"),
]

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scan.py (reported line 152)May include surrounding context.

python
Severity.HIGH, "Shell injection risk (shell=True)"),
    # Credential theft
    ("KGNhdHxyZWFkfG9wZW58bG9hZClzKy4qXC5lbnY=",
     Severity.CRITICAL, "Reading .env files"),
    ("KGNhdHxyZWFkfG9wZW58bG9hZClzKy4qXC5zc2gv",
     Severity.CRITICAL, "Reading SSH keys"),
    ("KGNhdHxyZWFkfG9wZW58bG9hZClzKy4qXy4oYXdzfGdudXBnfG5wbXJjL3BpcC8p",

Context-Inappropriate Capability

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The tool intentionally refuses to scan its own skill directory, creating a blind spot in a security product whose purpose is to audit skills. This allows malicious or unsafe content embedded in the scanner skill itself to evade detection and mislead users into trusting an unreviewed package.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scan.py (reported line 307)May include surrounding context.

python
return result

    # Files to skip
    skip_dirs = {'.git', 'node_modules', '__pycache__', '.venv', 'venv', '.env', 'dist', 'build'}
    skip_extensions = {'.png', '.jpg', '.jpeg', '.gif', '.ico', '.woff', '.woff2', '.ttf', '.eot',
                       '.mp3', '.mp4', '.wav', '.zip', '.tar', '.gz', '.pdf', '.doc', '.docx'}

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scan.py (reported line 337)May include surrounding context.

python
return result

    # Files to skip
    skip_dirs = {'.git', 'node_modules', '__pycache__', '.venv', 'venv', '.env', 'dist', 'build'}
    skip_extensions = {'.png', '.jpg', '.jpeg', '.gif', '.ico', '.woff', '.woff2', '.ttf', '.eot',
                       '.mp3', '.mp4', '.wav', '.zip', '.tar', '.gz', '.pdf', '.doc', '.docx'}

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill describes behavior that requires reading arbitrary skill files and likely scanning directories, but it does not declare an explicit tool scope such as permissions or allowed-tools. That mismatch can cause the agent runtime to grant or infer broader file-read capability than users expect, increasing the chance of overbroad access during audits.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The activation text uses broad phrases like auditing skills, checking skill security, verifying safety, and scanning before install, which can overlap with many general safety or review requests. This can cause the skill to trigger unexpectedly in unrelated contexts and influence security-sensitive workflows without the user intending to invoke it.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
81% confidence
Finding

The top-level documentation presents the scanner as purely local and network-free, but the implementation acknowledges that its own source contains patterns representing network activity and therefore skips self-scanning to avoid triggering on them. This creates an intent mismatch in the documentation: the file reads like a clean behavioral guarantee while the code is built around embedded network/exfiltration signatures that would flag its own contents.

Content

No source excerpt is available for this finding.

Ssd 2

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The code explicitly states that signatures are base64-encoded to avoid self-detection by naive scanners. Even if used for practical noise reduction, this is an obfuscation technique that weakens transparency and can conceal risky pattern content from reviewers and automated controls.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
80% confidence
Finding

The scanner explicitly treats environment-variable access as a sensitive operation, but this file includes no user-facing warning, confirmation, or logging around that behavior in the code itself. For a code file, accessing environment variables can expose credentials or other secrets and should be disclosed to the user.

Content

No source excerpt is available for this finding.

Unrestricted Tool Access

Medium
Category
Excessive Agency
Confidence
80% confidence
Finding

Skill grants unrestricted tool access without appropriate constraints. An agent with unfettered tool access can perform arbitrary actions including file modification, network requests, and code execution.

Content

Scanner excerpt · scan.py (reported line 233)May include surrounding context.

python
("ZnJvbVxzb3NcaW1wb3J0XHNzeXN0ZW0=",
     Severity.HIGH, "Direct OS command execution"),
    ("aW1wb3J0XHNwaWNrbGU=",
     Severity.MEDIUM, "Pickle deserialization (can execute arbitrary code)"),
    ("aW1wb3J0XHNtYXJzaGFs",
     Severity.MEDIUM, "Marshal deserialization"),
    ("aW1wb3J0XHNjdHlwZXM=",

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The code walks entire skill directories and reads file contents for analysis, which is a file-access operation affecting user data visibility. Although this is central to a scanner's purpose, the file lacks an explicit user-facing disclosure that local files will be recursively read and analyzed.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.