Back to skill

Security audit

Dynamic Skill Manager

Security checks for vulnerabilities and agentic risk

Overview

The skill has a legitimate skill-management purpose, but its uninstall function can delete installed skills without a direct confirmation step and has a verified symlink flaw that could remove the wrong or protected skill.

Install only if you are comfortable with a local tool that can modify and delete OpenClaw skill directories. Before using uninstall, verify the target directory yourself and avoid running cleanup automatically; the symlink and confirmation issues should be fixed before trusting it for routine skill removal.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/skill_manager.py:189
Finding

Protected Skill Deletion Through Symlink Resolution

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/skill_manager.py:251
Finding

Archive Path Traversal in Archived Skill Lookup

Content
View full analysis
Optional[dict]: """Get archived skill metadata for re-installation.""" archive_file = ARCHIVE_DIR / f"{skill_name}.json" if archive_file.exists(): return json.loads(archive_file.read_text()) return None ``` ### Technical Analysis `get_archived_skill()` incorporates `skill_name` directly into a filesystem path without calling `validate_skill_name()` or confirming that the resolved path remains under `ARCHIVE_DIR`. Path components such as `../` are therefore interpreted by the filesystem. The forced `.json` suffix limits accessible targets to paths ending in that suffix, but it does not prevent traversal outside the archive directory. If the resulting path identifies an existing JSON file readable by the process, the function reads and returns its parsed contents. The current command-line dispatcher does not expose this function directly, which reduces immediate exploitability. However, it is a public module function intended for integration, and another component may invoke it with attacker-controlled or insufficiently trusted input. ### Attack Path 1. An application imports `get_archived_skill()` and passes a Skill name influenced by an attacker. 2. The attacker supplies a traversal value such as `../../target`. 3. The function constructs `ARCHIVE_DIR / "../../target.json"`. 4. The operating system resolves the traversal components outside `ARCHIVE_DIR`. 5. If `target.json` exists and is readable by the process, `read_text()` reads it. 6. `json.loads()` parses the file and returns its contents to the caller. ### Impact Assessment The flaw can disclose JSON files outside the intended archive directory to any caller able to control `skill_name` and observe the retur ...[truncated 480 chars]
Remediation
View remediation
Optional[dict]: if not validate_skill_name(skill_name): raise ValueError("Invalid skill name") ``` 2. Resolve the archive root and candidate path, then enforce path-aware containment: ```python archive_root = ARCHIVE_DIR.resolve() archive_file = (ARCHIVE_DIR / f"{skill_name}.json").resolve() if not archive_file.is_relative_to(archive_root): raise ValueError("Archive path is outside the archive directory") ``` 3. Reject archive files that are symlinks before reading them if archive entries must always be regular files. 4. Open and parse files with explicit encoding and bounded input size to avoid excessive memory consumption from unexpectedly large files. 5. Add tests for `../`, backslash traversal, absolute paths, null bytes, symlinked archive entries, nonexistent files, malformed JSON, and valid archive names. ]]>
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (5)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding

The skill documents file-reading and file-writing behavior through its Python script usage and data locations, but it does not declare any explicit tool scope such as permissions or allowed-tools. In an agent environment, missing capability scoping can lead to overbroad file-system access being implicitly granted, increasing the chance of unintended reads, writes, or destructive lifecycle actions such as uninstall operations.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The 'Use when' section includes vague conditions such as 'User wants to see what skills are installed', 'User wants to uninstall or cleanup unused skills', and generic phrases like 'skill management' and 'dynamic skill'. These triggers are broad enough to overlap with common requests and do not clearly define activation boundaries or exclusions.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
86% confidence
Finding

This code performs irreversible deletion with shutil.rmtree() and archives metadata only optionally, but the function itself does not require explicit user confirmation before proceeding. Although there is a warning in the CLI usage path for missing arguments, a successful uninstall path only prints after deletion, so the safety-critical action lacks a direct pre-action confirmation or equivalent user disclosure at the point of execution.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
85% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · scripts/skill_manager.py (reported line 189)May include surrounding context.

python
Args:
        skill_name: Name of the skill to uninstall (must be safe directory name)
        archive: Whether to archive metadata before removal
        force: Skip confirmation (use with caution)
        
    Returns:
        True if successful, False if skill not found or validation failed

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The file presents significant instructional content and command annotations in Chinese, while other parts are in English, with no indication that the user can choose their preferred language. This can violate a language/locale policy when a specific language is imposed without opt-in or justification.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.