Back to skill

Security audit

Claw Self Evolution

Security checks for vulnerabilities and agentic risk

Overview

This skill is broadly aligned with self-maintenance, but it gives scheduled scripts high-impact authority over memory, files, logs, and service restarts with several under-scoped or misleading behaviors.

Review this skill carefully before installing. It is not just a passive helper: the recommended schedules can rewrite persistent user profile memory, copy sensitive workspace files into backups and caches, scan broad workspace metadata, delete old logs, merge experiment files into production, and restart a service. Install only in a controlled OpenClaw workspace after disabling or fixing the auto-profile, experiment merge/delete, service restart, backup/cache, and cleanup behaviors you do not explicitly want.

Vulnerability Patterns
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Tool Hijacking and SpoofingModifies or replaces tools so legitimate-looking calls execute attacker logic
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
Findings (8)

T02 · Agent Memory Poisoning

Error
Location
files/auto-update-user-profile.py:13
Finding

Persistent User-Profile Memory Poisoning Through Hard-Coded Preferences

Content
View full analysis
str: now = datetime.now().strftime("%Y-%m-%d %H:%M") new_insights = f""" ## 🎯 Latest Preference Summary ({now}) ### Directory Preferences - Strictly follow the OpenClaw directory structure - Logs must be stored under `/app/working/logs/` - Archived files must be stored under `scripts/legacy/` ### Security Preferences - Security must always take priority - Every Skill must be audited before installation - Sensitive information must be placed in `.secret/` ### Reporting Preferences - Feishu notifications must use Markdown tables - Output must be concise to save tokens ### Current Interests - Automatically send a daily fund-holding report to Feishu at 10:00 - The system should evolve itself and automatically propose optimizations """ if "## 🎯 Latest Preference Summary" in existing_content: parts = existing_content.split("## 🎯 Latest Preference Summary") base = parts[0] updated = base + new_insights else: updated = existing_content.rstrip() + "\n" + new_insights return updated def save_profile(content: str) -> None: with open(PROFILE_PATH, 'w', encoding='utf-8') as f: f.write(content) ``` The displayed strings above are an English rendering of the hard-coded preferences in the source. The write behavior and paths are unchanged. ### Technical Analysis The script claims to analyze recent conversations, but `CURRENT_SESSION` is never opened or parsed. Instead, `generate_profile_update()` creates a fixed set of behavioral rules, communication preferences, financial-reporting interest ...[truncated 1404 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
files/safe-experiment.py:27
Finding

Path Traversal Enables Writes and Deletions Outside Experiment Boundaries

Content
View full analysis
str: experiment_id = f"{datetime.now().strftime('%Y%m%d-%H%M')}-{experiment_name.replace(' ', '-')}" experiment_dir = os.path.join(EXPERIMENT_ROOT, experiment_id) os.makedirs(experiment_dir, exist_ok=True) def add_experiment_file(self, experiment_id: str, target_path: str, new_content: str) -> bool: experiment_dir = os.path.join(EXPERIMENT_ROOT, experiment_id) if os.path.exists(target_path): self.backup_original(target_path) rel_target = target_path.replace("/app/working/", "") experiment_file_path = os.path.join(experiment_dir, rel_target) os.makedirs(os.path.dirname(experiment_file_path), exist_ok=True) with open(experiment_file_path, "w", encoding='utf-8') as f: f.write(new_content) def approve_and_merge(self, experiment_id: str) -> Tuple[bool, str]: experiment_dir = os.path.join(EXPERIMENT_ROOT, experiment_id) info_path = os.path.join(experiment_dir, "experiment.json") with open(info_path, "r", encoding='utf-8') as f: info = json.load(f) core_files = ["jobs.json", "config.json", "chats.json", "copaw_file_metadata.json", "MEMORY.md"] is_core_modified = any( cf in f for f in info["files_modified"] for cf in core_files ) if is_core_modified: return False, "Core configuration requires secondary confirmation" for rel_file in info["files_modified"]: experiment_path = os.path.join(experiment_dir, rel_file) target_path = os.path.join("/app/working", rel_file) os.makedirs(os.path.dirname(target_path), exist_ok=True) shutil.copy2(experiment_path, target_path) def delete_experiment(self, ...[truncated 2130 chars]
Remediation
View remediation

T07 · Tool Hijacking and Spoofing

Error
Location
files/service-health-check.py:18
Finding

Broad Process Matching Can Terminate Unrelated Services and Execute a Spoofed Binary

Content
View full analysis
bool: result = subprocess.run( f"pgrep -f {PROCESS_NAME}", shell=True, capture_output=True, text=True ) return result.returncode == 0 and len(result.stdout.strip()) > 0 def try_restart_service() -> bool: if os.path.exists("/app/working/scripts/legacy/deploy/docker-compose.yaml"): result = subprocess.run( "cd /app/working && docker-compose restart", shell=True, capture_output=True, text=True, timeout=120 ) return result.returncode == 0 else: result = subprocess.run( f"pkill -f {PROCESS_NAME} && sleep 2 && " f"nohup {PROCESS_NAME} > /dev/null 2>&1 &", shell=True, capture_output=True, text=True, timeout=120 ) return result.returncode == 0 ``` ### Technical Analysis `pgrep -f` and `pkill -f` match the complete command line by substring, not a verified service identity. Any unrelated process whose arguments contain `copaw` can be considered healthy or can be terminated during restart. The restart command invokes `copaw` without an absolute path. The shell resolves it through `PATH`, so a malicious or unintended executable placed earlier in `PATH` can be launched. The same issue applies to `docker-compose`. The use of `shell=True` is unnecessary and expands the attack surface, although `PROCESS_NAME` is currently a constant rather than direct user input. ### Attack Path 1. The health check determines that the expected process is unavailable. 2. An attacker controls a writable directory listed early in the scheduled task’s `PATH`. 3. The attac ...[truncated 698 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Error
Location
files/daily-self-check.py:16
Finding

Scheduled Execution of Undeclared and Unpinned Local Skill Dependencies

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
files/core-backup.py:14
Finding

Sensitive Agent Data Is Duplicated into Unprotected Backups and Cache Files

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
install.sh:28
Finding

Install and Maintenance Operations Can Silently Destroy Existing Data

Content
View full analysis
"$WORKDIR/memory/learnings/ERRORS.md" << 'EOF' ... EOF cat > "$WORKDIR/memory/learnings/LEARNINGS.md" << 'EOF' ... EOF cat > "$WORKDIR/memory/learnings/FEATURE_REQUESTS.md" << 'EOF' ... EOF ``` ```python if dst_path.exists(): with open(src_path, 'r', encoding='utf-8') as f: new_content = f.read() with open(dst_path, 'a', encoding='utf-8') as f: f.write("\n\n--- Merged from memory root ---\n\n" + new_content) os.remove(src_path) else: shutil.move(str(src_path), str(dst_path)) if dst_path.exists(): os.remove(src_path) else: shutil.move(str(src_path), str(dst_path)) ``` ```python for root, dirs, files in os.walk(LOG_DIR): for filename in files: filepath = os.path.join(root, filename) stat = os.stat(filepath) mtime = datetime.datetime.fromtimestamp(stat.st_mtime) days_old = (today - mtime).days if days_old > RETENTION_DAYS: os.remove(filepath) ``` ### Technical Analysis The installer uses shell redirection to overwrite existing learning files without checking whether they contain user data. The directory verifier and undocumented cleanup script append content into colliding destinations and then remove the source. Runtime-log collisions cause unconditional source deletion without comparing file contents. The log cleaner recursively deletes every old file under the shared logs directory based only on modification time. It does not enforce a file extension, ownership requirement, approved subdirectory, quarantine period, dry run, or recovery mechanism. These operations are not transactional. A partial write, collision, unexpected fi ...[truncated 994 chars]
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
files/weekly-architecture-scan.py:25
Finding

Workspace-Wide Reconnaissance Exposes Unrelated File Metadata

Content
View full analysis
Remediation
View remediation

other

Warning
Location
files/weekly-introspection.py:151
Finding

Automated Introspection Reports Contain Unverified Fixed Claims

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (44)

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The module advertises automatic user-profile learning after each conversation, but the code only appends or replaces content with a canned summary. This mismatch can cause operators or other agents to rely on nonexistent analysis and treat persisted profile data as trustworthy, creating an integrity and deceptive-behavior risk in systems that reuse memory across sessions.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The function claims to update the profile based on the most recent conversation, but it never reads CURRENT_SESSION or any other session data and instead writes a hardcoded preference block. This is a security-relevant integrity issue because downstream components may trust the profile as user-derived state when it is actually fabricated, enabling misleading personalization, unsafe automation decisions, or policy bypass through false memory.

Content

No source excerpt is available for this finding.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
97% confidence
Finding

Using shell=True for operational checks is a classic tool-parameter abuse risk because the shell expands metacharacters, environment variables, and command chaining. In this skill context, the script is intended for automated privileged maintenance/self-check tasks, so any command injection or tampering with the command source becomes more dangerous because it can execute arbitrary maintenance-time actions and potentially expose sensitive output in generated reports.

Content

Scanner excerpt · files/daily-self-check.py (reported line 47)May include surrounding context.

python
"""运行单个检查,返回(是否成功, 标准输出, 标准错误)"""
    print(f"\n🔍 开始检查: {check['name']}")
    try:
        result = subprocess.run(
            check["command"],
            shell=True,
            capture_output=True,

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

The report claims human approval is required, but the code treats invocation of the approve path as sufficient and performs no independent verification of who approved, whether approval was recorded, or whether the request came from an authorized user. In an agent or automation context, this can let any caller that can trigger the command promote unreviewed experiment content directly into the production workspace.

Content

No source excerpt is available for this finding.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
90% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · files/service-health-check.py (reported line 19)May include surrounding context.

python
def is_process_running() -> bool:
    """检查进程是否在运行"""
    try:
        result = subprocess.run(
            f"pgrep -f {PROCESS_NAME}",
            shell=True,
            capture_output=True,

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
90% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · files/service-health-check.py (reported line 32)May include surrounding context.

python
def is_port_listening() -> bool:
    """检查端口是否在监听"""
    try:
        result = subprocess.run(
            f"ss -tulpn | grep :{CHECK_PORT}",
            shell=True,
            capture_output=True,

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
90% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · files/service-health-check.py (reported line 48)May include surrounding context.

python
try:
        # 尝试docker-compose重启
        if os.path.exists("/app/working/scripts/legacy/deploy/docker-compose.yaml"):
            result = subprocess.run(
                "cd /app/working && docker-compose restart",
                shell=True,
                capture_output=True,

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
90% confidence
Finding

This shell command combines process termination and background relaunch in a single string, including pattern-based pkill and nohup execution. Even though PROCESS_NAME is currently hardcoded, this design is dangerous in context because it performs privileged process control via shell syntax, can kill unintended matching processes, and would become command-injection-prone if the process name is ever externalized.

Content

Scanner excerpt · files/service-health-check.py (reported line 58)May include surrounding context.

python
return result.returncode == 0
        else:
            # 如果没docker,尝试直接重启进程
            result = subprocess.run(
                f"pkill -f {PROCESS_NAME} && sleep 2 && nohup {PROCESS_NAME} > /dev/null 2>&1 &",
                shell=True,
                capture_output=True,

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
90% confidence
Finding

Using subprocess.run with shell=True is dangerous because execution depends on shell parsing and environment resolution, which broadens the attack surface. Even though the command string is static here, a compromised PATH, shell environment, or aliased executable in the runtime context could cause unintended code execution or tampered results.

Content

Scanner excerpt · files/weekly-architecture-scan.py (reported line 131)May include surrounding context.

python
print("🔍 检查过时依赖...")
    
    try:
        result = subprocess.run(
            "pip list --outdated --format=json",
            shell=True,
            capture_output=True,

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill explicitly advertises automatic user profiling ('每天自动学习用户偏好,越来越懂用户') but does not disclose what interaction data is collected, how long it is retained, where it is stored, or how users can opt out. In a self-evolving agent skill, this creates a real privacy risk because profile-building can expand over time and silently accumulate behavioral data beyond user expectations.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill instructs ongoing construction of a user profile from interactions without meaningful consent, scope limitation, or safeguards. In context, this is more concerning because the skill is designed for continuous autonomous operation, so profiling can become persistent, opaque, and difficult for users to audit or stop.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The workflow and job examples are anchored to UTC+8/Beijing time, which imposes a locale-specific operating assumption in natural-language instructions. Because the document does not present this as optional or configurable for users in other locales, it conflicts with the policy against forcing a specific locale without opt-in.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

Several cron examples are described as conversions from Beijing time, making the skill's operational schedule locale-specific by default. The documentation does not offer language indicating that other locales are supported or that timezone selection is configurable, so this is a natural-language locale policy issue.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

This Python skill contains natural-language descriptions entirely in Chinese and presents the skill as automatically updating the user's profile, but it does not offer any language/locale choice or explain that it is intended only for Chinese-speaking users. The policy calls for flagging language or locale constraints when they are imposed without user opt-in or clear justification.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The skill is explicitly designed to persist conversation-derived preferences across sessions into a plaintext markdown profile. Persistent cross-session memory can capture sensitive behavioral, operational, or personal information and make it available to later runs or other components without clear minimization, consent, retention, or access controls.

Content

No source excerpt is available for this finding.

Ssd 3

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

Continuously summarizing recent conversations into a lasting profile creates a mechanism for retaining sensitive user-provided information beyond the original interaction. In an agent environment, such durable memory can be unintentionally reused, leaked, or influence future actions in ways the user did not expect, especially because the skill presents this behavior as automatic.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This code file contains natural-language descriptions and user-facing output exclusively in Chinese, including the module docstring and runtime status messages. Because the skill does not provide user opt-in, language selection, or a documented region-specific justification, it violates the language/locale policy criteria.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The top-level documentation says the script 'automatically scans system state, automatically fixes problems, and reports to Feishu if it cannot fix them.' In the implementation, only one check explicitly uses a '--fix' mode, there is no generic remediation logic, and there is no Feishu API/integration; instead the script writes a report and exits nonzero so an external scheduler may handle notification.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

This Python skill uses natural-language descriptions entirely in Chinese and presents itself as an automated daily self-check flow without any indication that language is configurable. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
95% confidence
Finding

The code executes command strings via subprocess.run with shell=True, which causes the shell to interpret the entire string. Even though the current CHECKS list is hardcoded, this pattern is dangerous in an agent/automation context because any future modification of the check definitions, environment influence, or path/command injection can lead to arbitrary command execution with the script's privileges.

Content

Scanner excerpt · files/daily-self-check.py (reported line 47)May include surrounding context.

python
"""运行单个检查,返回(是否成功, 标准输出, 标准错误)"""
    print(f"\n🔍 开始检查: {check['name']}")
    try:
        result = subprocess.run(
            check["command"],
            shell=True,
            capture_output=True,

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The module docstring and all user-facing messages are written only in Chinese, which imposes a specific language on users without any opt-in or alternative locale support. This matches the policy concern for language or locale constraints that are not documented as optional or region-specific.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The module docstring says '绝对不直接改生产,必须用户批准才会生效' and frames the workflow as isolated and approval-gated. However, the code includes an approve-and-merge path that copies files into /app/working, i.e. the production workspace, so the documentation overstates the safety boundary and omits that this tool performs direct production writes once invoked.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The module docstring and later user-facing output are written entirely in Chinese, including required approval wording, which imposes a specific language on users. The file does not provide an opt-in, alternative locale, or a documented reason that this skill must be Chinese-only.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The generated report instructs users to approve or reject experiments using fixed Chinese phrases, which effectively requires interaction in a specific language. There is no mechanism for users to choose another language or indication that the restriction is intentional and justified.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The module docstring states this is a health monitor for the OpenClaw service, but the hardcoded target process is copaw. That is a direct contradiction in stated intent versus implemented behavior, not merely missing detail.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.