Back to skill

Security audit

Self-Check Enhanced

Security checks for vulnerabilities and agentic risk

Overview

This self-check skill largely matches its stated purpose, but its diagnostic script runs broad local shell checks and has a real command-injection risk through log filenames.

Review before installing. Use it only if you are comfortable with a local diagnostic script reading OpenClaw configs, logs, selected skill files, environment-variable presence, disk and backup paths, and running shell commands. The log-reading command should be hardened to avoid shell interpretation before use on shared or untrusted systems.

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/self_check.py:501
Finding
Shell Command Injection Through a Crafted Log Filename<![CDATA[ ## Vulnerability Details **File Location**: `scripts/self_check.py`, lines 501–502 **Vulnerability Type**: OS command injection through unsafe shell interpolation **Risk Level**: Medium ### Vulnerable Code The selected log path is interpolated into a shell command: ```python latest_log = log_files[0] code, stdout, _ = run_cmd(f"tail -100 '{latest_log}'") ``` The invoked helper enables shell interpretation by default: ```python def run_cmd(cmd: str, shell: bool = True, timeout: int = 30) -> Tuple[int, str, str]: """运行命令并返回 (returncode, stdout, stderr)""" try: result = subprocess.run( cmd, shell=shell, capture_output=True, text=True, timeout=timeout ) return result.returncode, result.stdout.strip(), result.stderr.strip() except subprocess.TimeoutExpired: return -1, "", "Timeout" except Exception as e: return -1, "", str(e) ``` ### Technical Analysis The script finds the newest `*.log` file in `~/.openclaw/logs` and embeds its full path directly into a command string passed to `subprocess.run()` with `shell=True`. Although the path is surrounded by single quotes, POSIX filenames may themselves contain single-quote characters, semicolons, redirection operators, and other shell metacharacters. A single quote in the filename can terminate the intended quoted argument, after which the remaining filename content is parsed as shell syntax. For example, a filename resembling the following can introduce an additional command: ```text audit';id>self-check-proof;#.log ``` The resulting command is structurally equivalent to: ```sh tail -100 '/home/user/.openclaw/logs/audit';id>self-check-proof;#.log' ``` Consequently, the shell runs both `tail` and the injected `id` command. The issue is caused by combining attacker-influenced filesystem data with string-based shell execution; quoting alone does not safely handle embedded quote characters. ### Attack Path 1. An attacker obtains the ...[truncated 1702 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Do not pass the log path through a command shell. Invoke `tail` using an argument list and explicitly disable shell processing: ```python try: completed = subprocess.run( ["tail", "-100", str(latest_log)], shell=False, capture_output=True, text=True, timeout=30, ) code = completed.returncode stdout = completed.stdout.strip() except subprocess.TimeoutExpired: code, stdout = -1, "" ``` A broader hardening plan should include: 1. Refactor `run_cmd()` to accept a sequence of arguments and use `shell=False` by default: ```python def run_cmd(cmd: list[str], timeout: int = 30) -> Tuple[int, str, str]: result = subprocess.run( cmd, shell=False, capture_output=True, text=True, timeout=timeout, ) return result.returncode, result.stdout.strip(), result.stderr.strip() ``` 2. Convert commands that do not require shell features into argument arrays. 3. Replace shell pipelines and redirections with Python processing or explicitly connected subprocesses. 4. Avoid treating shell quoting as a substitute for argument-safe process invocation. 5. Add a regression test using a log filename containing quotes, semicolons, spaces, and redirection characters, verifying that no additional command executes. 6. Restrict permissions on `~/.openclaw/logs` so that only the intended user and trusted logging processes can create or rename files there. ]]>
Vulnerability Patterns
  • 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
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (7)

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill invokes a local Python script that performs broad system inspection, including environment variables, filesystem reads, shell execution, and potentially network-relevant checks, yet the manifest declares no explicit tool scope such as permissions or allowed-tools. This creates an overbroad, implicit trust boundary: a caller cannot tell what capabilities the skill requires, and an implementation could access sensitive files or secrets during 'self-check' operations without clear restriction or user-informed consent.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
The skill content is written entirely in Chinese, including the description, usage conditions, principles, checklist items, output format, and cautions, with no indication that language selection is optional. Under the policy, imposing a specific language without user opt-in is a natural-language policy violation unless the locale restriction is explicitly justified.

Natural-Language Policy Violations

Medium
Confidence
94% confidence
Finding
The top-level description and all user-facing status/report strings are written in Chinese, which effectively fixes the script's interaction language. There is no visible opt-in, locale selection, or justification that this skill is intentionally region-specific.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def run_cmd(cmd: str, shell: bool = True, timeout: int = 30) -> Tuple[int, str, str]:
    """运行命令并返回 (returncode, stdout, stderr)"""
    try:
        result = subprocess.run(
            cmd, shell=shell, capture_output=True, text=True, timeout=timeout
        )
        return result.returncode, result.stdout.strip(), result.stderr.strip()
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Context-Inappropriate Capability

Medium
Confidence
93% confidence
Finding
The self-check script goes beyond basic health validation and inspects environment variables and configuration files for secrets, including recursively scanning for key/token/secret-like fields. Even though it does not print secret values, this still expands the script's access to sensitive material and can reveal presence, storage locations, and naming conventions of credentials unrelated to a simple health check.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
else:
                result.add_issue(
                    f"权限 {d.name}: 所有者不正确 (uid={owner})",
                    f"sudo chown -R $(whoami):$(whoami) {d}",
                    "warning"
                )
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Missing User Warnings

Low
Confidence
89% confidence
Finding
The script reads sensitive environment variables and parses configuration files for secret-like fields without presenting a specific warning or consent prompt at the moment those checks execute. In a security-sensitive environment, silently touching credentials can violate least surprise and increase the risk of unintended disclosure through future logging, crashes, or downstream modifications.

Static analysis

No suspicious patterns detected.