Back to skill

Security audit

Skill Composer

Security checks for vulnerabilities and agentic risk

Overview

This workflow-composer skill has a coherent purpose, but it can invoke any installed skill and evaluates workflow conditions as Python code, creating review-worthy execution risk.

Install only if you trust the workflow files you will run and are comfortable with a skill that can invoke any installed OpenClaw skill. Prefer previewing workflows first, avoid third-party workflow YAML, and treat this as needing fixes before broad use: replace eval with a strict condition parser, fail closed on invalid conditions, pin dependencies, and restrict callable skills.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • 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)

T09 · Insecure Skill Coding Practices

Error
Location
source/composer.py:67
Finding
Arbitrary Code Execution Through Unsafe Workflow Condition Evaluation<![CDATA[ ## Vulnerability Details **File Location**: `source/composer.py:67-80` **Vulnerability Type**: Unsafe evaluation of attacker-controlled Python expressions **Risk Level**: High ### Vulnerable Code ```python try: return eval(condition, {"__builtins__": {}}) except: return True ``` ### Technical Analysis The application reads the `if` property of each workflow step directly from a YAML file and passes it to Python's `eval()` function. Although the evaluation globals replace `__builtins__` with an empty dictionary, this is not a secure sandbox. Python expressions can traverse the object model through attributes such as `__class__`, `__base__`, and `__subclasses__`. Depending on the classes loaded in the Python process, an attacker may locate a class that provides access to operating-system or subprocess functionality and use it to execute commands. The module imports `subprocess`, increasing the likelihood that useful process-related classes are available. Variable interpolation does not make the expression safe because it performs string replacement without parsing or restricting the resulting expression. In addition, the broad exception handler returns `True`, causing malformed or rejected conditions to fail open and execute the associated workflow step. ### Attack Path 1. An attacker creates or modifies a workflow YAML file accepted by the composer. 2. The attacker inserts a malicious Python expression into a step's `if` field. 3. A user invokes `composer.py run` with the attacker-controlled workflow. 4. `Workflow.load()` reads the expression without enforcing a restricted condition grammar. 5. `evaluate_condition()` substitutes available workflow variables into the expression. 6. The resulting expression is passed to `eval()`. 7. The expression traverses Python runtime objects to reach command-execution functionality. 8. The attacker's command executes with the operating-system privileges of the user running the composer. No shell me ...[truncated 732 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `eval()` entirely. Do not attempt to secure it only by removing built-ins. 2. Implement a small, explicit condition grammar supporting only required operations, such as: - Equality and inequality comparisons. - Boolean constants. - References to known step status values. - Boolean `and`, `or`, and `not`, if necessary. 3. Parse conditions into tokens or an abstract syntax tree and reject every node or operator not explicitly allowed. 4. Keep variable values separate from the condition syntax rather than inserting them through raw string replacement. 5. Validate variable names against a strict identifier pattern and permit only known workflow variables. 6. Restrict status comparisons to an allowlist such as `pending`, `success`, `failed`, `timeout`, and `skipped`. 7. Fail closed: if a condition is malformed or cannot be evaluated, report a validation error and stop or skip the step according to a documented policy. Do not return `True`. 8. Validate all conditions before any workflow step executes. 9. Add regression tests containing object traversal, attribute access, function calls, comprehensions, malformed expressions, and attempted imports to verify that they are rejected. ]]>

T08 · Insecure Dependencies

Note
Location
install.sh:20
Finding
Unpinned PyYAML Installation Creates Supply-Chain and Reproducibility Risk<![CDATA[ ## Vulnerability Details **File Location**: `install.sh:20-22`; related declaration at `skill.json:28-35` **Vulnerability Type**: Unpinned third-party dependency installation **Risk Level**: Low ### Vulnerable Code ```bash elif command -v pip3 &> /dev/null; then echo "Installing PyYAML via pip..." pip3 install --user PyYAML ``` The related manifest permits any release satisfying a lower bound and instructs the installer to obtain an unspecified version: ```json "requirements": { "bins": ["python3"], "python": ["PyYAML>=5.4"] }, "install": [ { "id": "python-pyyaml", "kind": "pip", "package": "PyYAML", "label": "Install PyYAML dependency" } ] ``` ### Technical Analysis The pip fallback installs whichever PyYAML release is selected by the package index at installation time. The project does not pin a reviewed version or verify an artifact hash. The manifest similarly accepts any PyYAML version at or above 5.4. This does not demonstrate that PyYAML itself is malicious. The weakness is that separate installations may receive different, previously unreviewed artifacts. A compromised upstream release, package-index account, distribution channel, or future incompatible version could therefore affect installation without any change to this project's reviewed source. Python package installation may execute package build logic under the invoking user's account. Consequently, dependency integrity is relevant even before the composer is run. ### Attack Path 1. The installer runs on a system where `apt-get` is unavailable and `pip3` is present. 2. `pip3 install --user PyYAML` queries the configured package index. 3. The resolver selects the latest compatible artifact because no exact version or hash is required. 4. If the selected upstream artifact or configured index is compromised, malicious installation or runtime code is placed in the user's Python environment. 5. Installation-time code or a later `import yaml` execute ...[truncated 619 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Pin PyYAML to an exact, reviewed version rather than using an unconstrained package name or minimum-only version. 2. Record cryptographic hashes for approved distributions and install with hash verification, for example through a locked requirements file and `--require-hashes`. 3. Keep the manifest and installation script synchronized so both enforce the same version. 4. Use `python3 -m pip` to ensure installation targets the interpreter that runs the composer. 5. Install dependencies in an isolated virtual environment instead of modifying the user's shared Python environment. 6. Use a trusted package index explicitly and protect any internal mirror against unauthorized publication. 7. Add automated dependency scanning and a controlled process for reviewing and updating the pinned version. 8. If APT remains supported, document that distribution repositories may provide a separately maintained version and define the minimum security patch level required. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (14)

eval() call detected

High
Category
Dangerous Code Execution
Content
condition = condition.replace(placeholder, str(var_value))
        # 安全评估
        try:
            return eval(condition, {"__builtins__": {}})
        except:
            return True  # 默认执行
Confidence
99% confidence
Finding
The workflow file is attacker-controlled input, and this code evaluates its `if` condition with Python `eval()`. Even with `__builtins__` removed, `eval` on untrusted expressions is unsafe and can often be abused for denial of service or sandbox escape techniques, while the fallback `except: return True` also causes malformed or malicious conditions to execute steps by default.

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill is explicitly designed to orchestrate execution of other skills and its documentation shows shell-based invocation of a Python runner, yet the manifest declares no tool scope such as permissions or allowed-tools. That means a user or platform cannot easily understand or constrain the file-read and command-execution capabilities implied by the workflow engine, increasing the chance of unexpected downstream file access or side effects from composed skills.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
This skill is a workflow composer that chains arbitrary skills, including examples that publish content externally, but the user-facing description does not warn that execution can trigger file writes, external publishing, or other side effects through downstream skills. In this context, missing disclosure is security-relevant because users may treat the composer as a harmless planner when it actually acts as a privileged orchestrator.

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
The file’s human-readable title and step descriptions are entirely in Chinese, and the pipeline is specifically oriented to Chinese platforms like WeChat and Xiaohongshu without offering a language or locale choice. Under the policy rule, forcing a specific language or locale without user opt-in is a natural-language policy concern unless the regional constraint is explicitly documented and justified.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
This manifest contains user-facing natural language almost entirely in Chinese, including the title, step names, and usage notes. Because it does not offer an opt-in language choice or state that the skill is intentionally limited to Chinese-speaking users or a China-specific workflow, it may violate language/locale policy requirements.

Vague Triggers

Medium
Confidence
88% confidence
Finding
This YAML file includes only a high-level description of automating a data report and lists related skills, but it does not specify any explicit trigger phrases, scope limits, or exclusion conditions. In a manifest-style file, that ambiguity can cause the skill to be invoked for loosely related requests about reports or stocks without clear boundaries.

Vague Triggers

Medium
Confidence
93% confidence
Finding
The manifest explicitly declares `"skills": ["*"]`, allowing this composer skill to invoke or orchestrate any installed skill without scope restriction. In an automation/orchestration context, that broad capability increases blast radius: a malicious or unsafe workflow file could chain together high-privilege skills, access sensitive operations indirectly, or bypass intended least-privilege boundaries between skills.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The module docstring is written in Chinese and presents the skill description and inline documentation in that language without any indication that the user can choose another language. This is a natural-language locale policy concern because the file appears to impose a language preference rather than documenting an optional or region-specific constraint.

Context-Inappropriate Capability

Medium
Confidence
98% confidence
Finding
The workflow engine expands variables into manifest-supplied conditions and then evaluates them as Python expressions, introducing code-execution-like behavior into a data file that should only describe orchestration. This is especially risky because the tool is explicitly designed to compose multiple skills automatically, so a bypassed or malicious condition can trigger unintended downstream actions across the workflow.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
print(f"     Args: {args}")

        try:
            result = subprocess.run(cmd, capture_output=True, text=True, timeout=300)
            if result.returncode == 0:
                return 'success', result.stdout
            else:
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Natural-Language Policy Violations

Low
Confidence
87% confidence
Finding
The manifest description forces a specific language/locale in user-facing natural language without indicating user choice or that the skill is restricted to a Chinese-speaking audience. Under the policy, locale-specific language should be optional or clearly justified.

Natural-Language Policy Violations

Low
Confidence
84% confidence
Finding
The entire SKILL.md is presented in Chinese, and there is no note that the skill is region- or locale-specific, nor any offer of alternative language support. This can violate language/locale policy when users are not given a choice.

Natural-Language Policy Violations

Low
Confidence
97% confidence
Finding
The file's user-facing descriptive comments are entirely in Chinese, which implicitly fixes the skill's language context without offering any user choice or documenting a justified locale restriction. This can conflict with organizational language/locale policy when users have not opted into that language.

Natural-Language Policy Violations

Low
Confidence
84% confidence
Finding
The natural-language description is written solely in Chinese, and the manifest does not indicate that language choice is optional or region-specific. This can violate language/locale policy expectations when a skill is presented to a broader user base without opt-in or justification.

Static analysis

Detected: suspicious.dynamic_code_execution

Dynamic code execution detected.

Critical
Code
suspicious.dynamic_code_execution
Location
source/composer.py:74