Back to skill

Security audit

Team Resurrection

Security checks for vulnerabilities and agentic risk

Overview

This migration skill has a coherent purpose, but it can overwrite active agent state, install skills and scheduled tasks, and write to broad local paths with incomplete review safeguards.

Install only if you trust the source and will use it on migration packages you created yourself. Before restoring, inspect the archive contents, run dry-run where available, prefer --no-cron and --no-restart first, and do not let untrusted packages install skills or scheduled tasks into an active OpenClaw profile.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • System PersistenceInstalls backdoors, hooks, services, or scheduled tasks that survive the run
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
Findings (7)

T01 · Skill Instruction Hijacking

Error
Location
migrate.py:303
Finding

Untrusted migration files can overwrite persistent Agent instructions and memory

Content
View full analysis

Vulnerability Details

File Location: migrate.py:303-316
Vulnerability Type: Persistent instruction and memory poisoning
Risk Level: Critical

Vulnerable Code

python
copied = 0
for fname in ["SOUL.md", "MEMORY.md", "TOOLS.md", "AGENTS.md", "IDENTITY.md", "USER.md"]:
    src = identity_dir / fname
    if src.exists():
        shutil.copy2(src, ws_path / fname)
        copied += 1

memory_src = identity_dir / "memory"
if memory_src.exists():
    memory_dst = ws_path / "memory"
    memory_dst.mkdir(parents=True, exist_ok=True)
    for f in memory_src.glob("*.md"):
        shutil.copy2(f, memory_dst / f.name)
    copied += 1

Technical Analysis

The migration package controls the contents of SOUL.md, AGENTS.md, TOOLS.md, MEMORY.md, IDENTITY.md, USER.md, and historical memory files. These files are copied directly over files in the live main Agent workspace.

The review process only lists the filenames at migrate.py:721-738; it does not display their contents or a complete diff. A malicious package can therefore contain persistent behavioral instructions while presenting ordinary, expected filenames to the user.

Because these files define Agent identity, operating instructions, tool guidance, user context, and persistent memory, this is more security-sensitive than an ordinary file overwrite.

Attack Path

  1. An attacker creates or modifies a migration package.
  2. The attacker places malicious instructions in SOUL.md, AGENTS.md, or TOOLS.md.
  3. The attacker places persistent false rules or state in MEMORY.md or memory/*.md.
  4. The victim runs migrate.py and sees only the expected filenames during review.
  5. The victim confirms the migration.
  6. The files overwrite the active Agent workspace.
  7. Future Agent sessions load and follow the attacker-controlled instructions or poisoned memory.

Impact Assessment

Successful exploitation can alter current and future Agent behavior, replace safety or operat ...[truncated 212 chars]

Remediation
View remediation

Remediation Suggestions

  • Restore identity and memory files into a quarantined workspace rather than the active workspace.
  • Display complete unified diffs for every instruction-bearing or memory-bearing file.
  • Require separate approval for SOUL.md, AGENTS.md, TOOLS.md, MEMORY.md, and the memory/ directory.
  • Do not overwrite existing files by default. Use versioned copies and an explicit promotion step.
  • Reject unexpected file types, symbolic links, and files outside a strict allowlist.
  • Support package signing and verify the package against a trusted public key before restoration.
  • Record cryptographic hashes of reviewed files and verify that the same bytes are copied after approval.

T05 · Unauthorized Access and Privilege Escalation

Error
Location
migrate.py:349
Finding

Package-controlled workspace paths allow writes outside the intended OpenClaw directory

Content
View full analysis

Vulnerability Details

File Location: migrate.py:349-376
Vulnerability Type: Unrestricted filesystem destination
Risk Level: High

Vulnerable Code

python
# Read openclaw-agents.json to obtain each member's actual workspace path
agents_file = package_dir / "openclaw-agents.json"
member_workspaces = {}
if agents_file.exists():
    try:
        agents_data = load_json(agents_file)
        for a in agents_data.get('agents', {}).get('list', []):
            if a.get('id') != 'main' and a.get('workspace'):
                member_workspaces[a.get('name', a.get('id'))] = a['workspace']
    except:
        pass

count = 0
for member_dir in team_dir.iterdir():
    if member_dir.is_dir():
        member_name = member_dir.name
        if member_name in member_workspaces:
            dst = Path(member_workspaces[member_name])
        else:
            dst = main_ws_path / member_name
        dst.mkdir(parents=True, exist_ok=True)
        for fname in ["SOUL.md", "MEMORY.md", "TOOLS.md"]:
            src = member_dir / fname
            if src.exists():
                shutil.copy2(src, dst / fname)
        count += 1

Technical Analysis

The destination path is read directly from package-controlled openclaw-agents.json. The code does not canonicalize the path, enforce that it is below ~/.qclaw, reject absolute paths, or check for symbolic-link traversal.

Consequently, a package can map a team member name to any writable filesystem directory. The migration then creates that directory and writes files into it.

Attack Path

  1. An attacker adds an Agent entry to openclaw-agents.json.
  2. The entry's name matches a directory under 团队成员层/.
  3. The entry's workspace points to an attacker-selected absolute or traversal-based path.
  4. The matching member directory contains SOUL.md, MEMORY.md, or TOOLS.md.
  5. The victim approves and runs the migration.
  6. migrate.py creates the selected directory and writes the package files th ...[truncated 324 chars]
Remediation
View remediation

Remediation Suggestions

  • Resolve every destination with Path.resolve() before creating directories or copying files.
  • Require all member workspaces to be descendants of a dedicated root such as ~/.qclaw/workspaces.
  • Reject absolute paths, .. components, symbolic-link escapes, and paths outside the approved root.
  • Derive destination paths locally from validated Agent IDs instead of trusting paths from the package.
  • Validate Agent IDs and names using a conservative allowlist.
  • Refuse to overwrite existing destination files unless the complete destination and diff were approved.
  • Perform validation before any filesystem or configuration mutation.

T06 · System Persistence

Error
Location
migrate.py:424
Finding

Migration packages can install arbitrary persistent scheduled Agent payloads

Content
View full analysis

Vulnerability Details

File Location: migrate.py:424-463
Vulnerability Type: Unvalidated scheduled-task installation
Risk Level: Critical

Vulnerable Code

python
def create_cron_tasks(package_dir):
    """Create cron tasks after user review."""
    info("Creating cron tasks...")

    cron_file = package_dir / "cron_tasks.json"
    if not cron_file.exists():
        cron_file = package_dir / "cron_jobs.json"
    if not cron_file.exists():
        warn("  No cron configuration found")
        return True

    cron_tasks = load_json(cron_file)

    output, _ = run_cmd("openclaw tasks list --json 2>/dev/null")
    try:
        existing = json.loads(output) if output else []
        existing_names = {t.get('name', '') for t in existing}
    except:
        existing_names = set()

    created = 0
    skipped = 0
    failed = 0

    for task in cron_tasks:
        task_name = task.get('name', 'unnamed')

        if task_name in existing_names:
            skipped += 1
            info(f"  Skipping existing task: {task_name}")
            continue

        task_json = json.dumps(task, ensure_ascii=False)
        result = subprocess.run(
            ["openclaw", "tasks", "add", "--job", task_json],
            capture_output=True, text=True
        )

Technical Analysis

The full scheduled-job object is accepted from the migration package and passed to openclaw tasks add. There is no allowlist for job types, payload operations, target Agents, or execution frequency.

The review code at migrate.py:714-718 converts the payload to a string and truncates it to 80 characters. A harmful continuation can therefore be concealed after a benign prefix even though the complete payload is installed.

This behavior creates a cross-session execution mechanism controlled by the migration archive.

Attack Path

  1. An attacker adds a scheduled job to cron_tasks.json.
  2. The payload begins with harmless-looking text and places malicious instruct ...[truncated 622 chars]
Remediation
View remediation

Remediation Suggestions

  • Disable scheduled-task migration by default.
  • Require an explicit command-line option and separate approval for each task.
  • Display the complete canonical task JSON without truncation.
  • Validate tasks against a strict schema and an allowlist of permitted job kinds, schedules, targets, and payload fields.
  • Reject payloads capable of invoking commands or privileged tools unless separately authorized.
  • Cap task frequency to prevent high-frequency persistent execution.
  • Record every installed task ID and provide automatic rollback if a later migration step fails.
  • Consider exporting task definitions for manual installation rather than registering them automatically.

T09 · Insecure Skill Coding Practices

Error
Location
migrate.py:140
Finding

Dry-run configuration merge differs from the configuration written during real execution

Content
View full analysis

Vulnerability Details

File Location: migrate.py:140-145 and migrate.py:832-852
Vulnerability Type: Security review and execution inconsistency
Risk Level: High

Vulnerable Code

Real execution uses generic deep merging:

python
if 'agents' in agents_patch:
    if 'agents' not in merged:
        merged['agents'] = {}
    merged['agents'] = deep_merge(merged['agents'], agents_patch['agents'])

The underlying deep_merge() replaces non-dictionary values, including lists:

python
def deep_merge(base, patch):
    result = base.copy()
    for k, v in patch.items():
        if k in result and isinstance(result[k], dict) and isinstance(v, dict):
            result[k] = deep_merge(result[k], v)
        else:
            result[k] = v
    return result

Dry-run instead merges agents.list by Agent ID:

python
if 'list' in agents_patch['agents']:
    if 'list' not in merged['agents']:
        merged['agents']['list'] = []
    existing_ids = {a.get('id') for a in merged['agents']['list']}
    for agent in agents_patch['agents']['list']:
        aid = agent.get('id')
        if aid in existing_ids:
            merged['agents']['list'] = [
                agent if a.get('id') == aid else a
                for a in merged['agents']['list']
            ]
        else:
            merged['agents']['list'].append(agent)

Technical Analysis

During real execution, deep_merge() replaces agents.list because lists are not dictionaries. During dry-run, existing Agents are retained and package Agents are updated or appended by ID.

The user can therefore approve a preview that shows additive behavior, while real execution writes a configuration that removes existing Agent entries. This also contradicts the review statement that existing Agents will not be deleted.

Attack Path

  1. A migration package supplies an agents.list containing only attacker-selected or migrated Agents.
  2. The victim runs --dry-run.
  3. Dry-run retai ...[truncated 584 chars]
Remediation
View remediation

Remediation Suggestions

  • Implement a single pure merge function and use it for both dry-run and real execution.
  • Merge agents.list by stable Agent ID rather than replacing the entire list.
  • Generate the approval diff from the exact final object that will be written.
  • Serialize and hash the approved configuration, then verify the hash immediately before writing.
  • Add tests proving that dry-run output and real execution produce identical results.
  • Abort if the final configuration differs from the reviewed configuration.
  • Explicitly highlight removals, workspace changes, hook changes, and permission changes.

T04 · Embedded Malicious Code

Error
Location
migrate.py:386
Finding

Unreviewed package skills are recursively merged into the active execution environment

Content
View full analysis

Vulnerability Details

File Location: migrate.py:386-418
Vulnerability Type: Untrusted Skill installation and overwrite
Risk Level: High

Vulnerable Code

python
def copy_skills(package_dir):
    """Copy skills."""
    info("Copying skills...")

    skills_src = package_dir / "skills"
    if not skills_src.exists():
        warn("  No skills detected")
        return True

    workspace_base = Path.home() / ".qclaw"

    main_ws = None
    config_path = workspace_base / "openclaw.json"
    if config_path.exists():
        config = load_json(config_path)
        for agent in config.get('agents', {}).get('list', []):
            if agent.get('id') == 'main':
                main_ws = agent.get('workspace', '')
                break

    if not main_ws:
        candidates = [d for d in workspace_base.iterdir()
                      if d.is_dir() and d.name.startswith("workspace-")]
        if candidates:
            main_ws = str(candidates[0])

    if main_ws:
        ws_path = Path(main_ws)
    else:
        ws_path = workspace_base / "workspace-main"

    skills_dst = ws_path / "skills"
    skills_dst.mkdir(parents=True, exist_ok=True)

    count = 0
    for skill_dir in skills_src.iterdir():
        if skill_dir.is_dir():
            dst = skills_dst / skill_dir.name
            shutil.copytree(skill_dir, dst, dirs_exist_ok=True)
            count += 1

Technical Analysis

Every directory under the package's skills/ directory is recursively copied into the active main workspace. dirs_exist_ok=True allows files belonging to an existing trusted Skill to be overwritten.

The confirmation stage only lists Skill directory names, not file contents, executable scripts, hashes, or diffs. A malicious package can consequently use the name of a trusted Skill while replacing its SKILL.md or scripts.

Attack Path

  1. An attacker includes a Skill directory with a trusted-looking or existing name.
  2. The directory contains malicious ...[truncated 609 chars]
Remediation
View remediation

Remediation Suggestions

  • Restore Skills to a quarantine directory and never activate them automatically.
  • Display complete file inventories, hashes, and diffs before installation.
  • Refuse to overwrite an existing Skill unless the exact changes receive separate approval.
  • Require trusted digital signatures for imported Skills.
  • Validate that Skill directories contain no symbolic links, device files, or paths escaping the package.
  • Separate instruction-only Skills from executable Skills and apply stricter approval to executable content.
  • Maintain an immutable or hash-pinned baseline for trusted Skills.

T09 · Insecure Skill Coding Practices

Error
Location
clone.py:119
Finding

Unvalidated clone suffix permits path traversal in workspace and Agent directory destinations

Content
View full analysis

Vulnerability Details

File Location: clone.py:119-144, with input accepted at clone.py:278-289
Vulnerability Type: Path traversal through clone suffix
Risk Level: High

Vulnerable Code

python
def rename_workspace_path(original_path: str, suffix: str) -> str:
    """Append a suffix to a workspace path."""
    p = Path(original_path)
    return str(p.parent / f"{p.name}-{suffix}")


def rename_agentdir_path(original_path: str, suffix: str) -> str:
    """Append a suffix to an agentDir path."""
    p = Path(original_path)
    return str(p.parent / f"{p.name}-{suffix}")


def safe_copytree(src: Path, dst: Path, label: str = ""):
    """Copy a directory unless the destination exists."""
    if dst.exists():
        warn(f"  Destination already exists, skipping: {dst.name}")
        return False
    shutil.copytree(src, dst)
    log(f"  Copied {label or src.name} to {dst.name}")
    return True

The suffix is accepted without validation:

python
suffix = "copy"
if "--suffix" in sys.argv:
    idx = sys.argv.index("--suffix")
    if idx + 1 < len(sys.argv):
        suffix = sys.argv[idx + 1]
else:
    user_input = input("Enter clone suffix: ").strip()
    if user_input:
        suffix = user_input

Technical Analysis

The suffix is concatenated into filesystem paths without restricting path separators, traversal components, length, or control characters. A suffix containing separators and .. components can alter the effective destination after path normalization.

shutil.copytree() then recursively copies the complete workspace or Agent directory to that destination. There is no containment check confirming that the resolved destination remains under the expected parent.

Attack Path

  1. The clone operation is invoked with a crafted suffix containing path separators or traversal components.
  2. rename_workspace_path() or rename_agentdir_path() constructs a destination containing those components.
  3. The destination ...[truncated 502 chars]
Remediation
View remediation

Remediation Suggestions

  • Restrict suffixes to a conservative pattern such as ^[A-Za-z0-9_-]{1,32}$.
  • Reject /, \, .., leading dots, control characters, and absolute-path syntax.
  • Resolve the destination and verify that it remains directly beneath the expected parent directory.
  • Use a generated clone identifier instead of using raw user input in filesystem paths.
  • Apply the same containment validation to workspace and agentDir destinations.
  • Abort the entire clone if any destination fails validation or any copy operation fails.

T09 · Insecure Skill Coding Practices

Warning
Location
migrate.py:435
Finding

Bundled cron schema can crash migration after partial security-sensitive changes

Content
View full analysis

Vulnerability Details

File Location: migrate.py:435-451 and cron_tasks.json:1-15
Vulnerability Type: Schema confusion and non-transactional migration
Risk Level: Medium

Vulnerable Code

The migration expects a top-level list:

python
cron_tasks = load_json(cron_file)

output, _ = run_cmd("openclaw tasks list --json 2>/dev/null")
try:
    existing = json.loads(output) if output else []
    existing_names = {t.get('name', '') for t in existing}
except:
    existing_names = set()

created = 0
skipped = 0
failed = 0

for task in cron_tasks:
    task_name = task.get('name', 'unnamed')

The bundled file instead contains an object with a nested tasks list:

json
{
  "description": "Cron task list example",
  "note": "This is a template file",
  "tasks": [
    {
      "name": "main daily self-iteration",
      "schedule": "cron 0 22 * * * Asia/Shanghai",
      "sessionTarget": "isolated",
      "payload": {
        "kind": "agentTurn",
        "message": "Perform daily self-iteration."
      }
    }
  ]
}

Technical Analysis

Iterating over a JSON object yields its string keys. The subsequent task.get(...) call therefore raises an exception because a string does not provide the expected dictionary interface.

Cron creation occurs after identity files, team files, Skills, and Agent configuration have already been modified. The migration does not use a transaction and does not automatically restore its backup when a later stage fails.

Attack Path

  1. The victim uses the bundled cron schema or receives a similarly malformed migration package.
  2. The victim approves and begins migration.
  3. Identity, team, Skill, and configuration writes complete.
  4. Cron processing iterates over object keys.
  5. task.get(...) raises an exception.
  6. The process terminates with earlier modifications still present and without automatic rollback.

Impact Assessment

The environment can be left partially migrated and internally inconsis ...[truncated 188 chars]

Remediation
View remediation

Remediation Suggestions

  • Define and enforce one documented JSON schema for cron configuration.
  • If the object format is retained, explicitly access and validate document["tasks"].
  • Validate all package configuration before requesting confirmation or modifying the system.
  • Reject malformed tasks with clear errors rather than continuing.
  • Make migration transactional: stage changes, validate them, then commit atomically.
  • Automatically restore the backup and remove newly created tasks or directories if any stage fails.
  • Stop reporting overall success when an individual migration step fails.
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
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
Findings (37)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The skill description says packaging is limited and confirms actions before execution, but the documented contents include highly sensitive files such as MEMORY.md, TOOLS.md, USER.md, AGENTS.md, identity data, cron tasks, and migration scripts. This mismatch is dangerous because it normalizes exporting secrets and operational artifacts under a benign 'backup/move team' label, increasing the chance of unreviewed data exfiltration or unsafe restore execution.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The skill description says packaging is limited and confirms actions before execution, but the documented contents include highly sensitive files such as MEMORY.md, TOOLS.md, USER.md, AGENTS.md, identity data, cron tasks, and migration scripts. This mismatch is dangerous because it normalizes exporting secrets and operational artifacts under a benign 'backup/move team' label, increasing the chance of unreviewed data exfiltration or unsafe restore execution.

Content

No source excerpt is available for this finding.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
90% confidence
Finding

The documented remediation instructs use of rm -rf on a workspace path, which is inherently dangerous if the path is mistyped, expanded unexpectedly, or copied into automation without validation. In a skill centered on filesystem migration and cloning, normalizing recursive forced deletion increases the risk of accidental data loss in a sensitive agent workspace area.

Content

Scanner excerpt · SKILL.md (reported line 378)May include surrounding context.

解决: 换一个后缀,或手动删除旧分身:

bash
rm -rf ~/.qclaw/workspace-xxx-旧后缀
# 然后从 openclaw.json 中删除对应 agent 条目

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
90% confidence
Finding

The documented remediation instructs use of rm -rf on a workspace path, which is inherently dangerous if the path is mistyped, expanded unexpectedly, or copied into automation without validation. In a skill centered on filesystem migration and cloning, normalizing recursive forced deletion increases the risk of accidental data loss in a sensitive agent workspace area.

Content

Scanner excerpt · SKILL.md (reported line 378)May include surrounding context.

解决: 换一个后缀,或手动删除旧分身:

bash
rm -rf ~/.qclaw/workspace-xxx-旧后缀
# 然后从 openclaw.json 中删除对应 agent 条目

Description-Behavior Mismatch

High
Category
Not specified by scanner
Confidence
98% confidence
Finding

The skill metadata advertises safety controls such as --dry-run, --no-cron, and --no-restart, but the implementation always performs live filesystem changes and always restarts the gateway after a single prompt. This mismatch is dangerous because operators may rely on the advertised controls during migration/cloning and unintentionally trigger disruptive or irreversible actions in a privileged local environment.

Content

No source excerpt is available for this finding.

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
99% confidence
Finding

This is a true tool-parameter abuse issue because the function accepts an arbitrary command string and runs it via the shell. In a migration script handling potentially adversarial package content and task configuration, any future or indirect flow of package-derived data into run_cmd could lead to arbitrary local code execution with the user's privileges.

Content

Scanner excerpt · migrate.py (reported line 43)May include surrounding context.

python
def info(msg):  print(f"{BLUE}[i]{NC} {msg}")

def run_cmd(cmd):
    result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
    return result.stdout.strip(), result.returncode

# =============================================

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 · clone.py (reported line 44)May include surrounding context.

python
def info(msg): print(f"{BLUE}[i]{NC} {msg}")

def run_cmd(cmd):
    result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
    return result.stdout.strip(), result.returncode

# =============================================

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 · pack.py (reported line 32)May include surrounding context.

python
def info(msg): print(f"{BLUE}[i]{NC} {msg}")

def run_cmd(cmd):
    result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
    return result.stdout.strip(), result.returncode

# =============================================

Ssd 3

High
Category
Not specified by scanner
Confidence
96% confidence
Finding

The README explicitly instructs users to hand the package to an agent for automated migration, even though the package contains sensitive workspace contents, member data, skills, and potentially cron/task metadata. Delegating execution of a sensitive bundle to another agent increases the chance of overbroad access, unintended disclosure, or unauthorized actions in a new environment.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

High
Category
Not specified by scanner
Confidence
94% confidence
Finding

The generated README claims that execution will display all changes for user confirmation, but this script itself creates packaging artifacts and automation instructions without implementing such confirmation. That mismatch can mislead users into trusting downstream automation with sensitive data under a false assurance of review and consent.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The changelog advertises a 'clone/resurrection' feature that scans sub-agent sessions, finds continuation points, and creates a new agent inheriting memory, which goes beyond the stated packaging/migration scope in the skill metadata. This capability materially changes the trust boundary: it implies session discovery and state carryover, which can expose sensitive conversation history, credentials, or authorization context if users invoke the skill expecting only backup/migration behavior.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill metadata says it preserves only SOUL.md, team members, and skills, but the packing spec clearly includes broader identity artifacts such as MEMORY.md, TOOLS.md, IDENTITY.md, USER.md, and history data. This mismatch can cause users to authorize migration under a narrower mental model, leading to unintended transfer of sensitive data and over-broad access to personal or operational information.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The documentation states that USER.md, MEMORY.md, TOOLS.md, and memory/history content are packaged and migrated, but it does not warn that these may contain personal data, secrets, identifiers, or sensitive operational context. In a migration package that may be moved across systems or shared manually, omission of a privacy warning materially increases the risk of accidental exposure.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The workflow includes state-changing operations such as updating openclaw configuration, creating cron jobs, and restarting Gateway, yet the document lacks a centralized risk notice explaining operational impact. Without an explicit warning, users may underestimate the persistence, privilege, and availability implications of running the migration script.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The documented workflow goes beyond simple export/import and performs system-affecting actions including configuration modification, cron creation, and Gateway restart. If a user expects only data migration, these additional side effects can alter service behavior, persistence, and availability in ways they did not meaningfully approve.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The skill description is written entirely in Chinese and does not indicate that other languages are supported or that Chinese is a required locale for a region-specific use case. Under the policy, forcing a specific language without user opt-in is a natural-language policy concern.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
70% confidence
Finding

Without declared permissions the skill's intent is opaque and cannot be validated.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The trigger phrases are broad enough to match ordinary user requests like 'backup team' or 'I changed computers,' which can cause this high-impact skill to activate unexpectedly. In this context, accidental activation is more dangerous than usual because the skill is designed to read sensitive files, modify runtime config, create cron jobs, and restart services.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

Natural-language policy violations apply to all file types, including code comments, docstrings, and string literals. This script presents its purpose, workflow, and later prompts in Chinese only, which can force a locale/language on users who were not given an option to choose another language.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
83% confidence
Finding

The manifest describes packaging/moving/cloning team configuration with emphasis on preserving specific configuration artifacts such as SOUL.md, members, and skills. In contrast, this script recursively copies every file in each workspace and agentDir via shutil.copytree, which exceeds the narrower described configuration-preservation behavior and may duplicate unrelated local data.

Content

No source excerpt is available for this finding.

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script modifies agents.defaults.subagents.allowAgents and hooks.allowedAgentIds by appending all cloned agent IDs during a cloning workflow. Expanding authorization lists changes trust boundaries and privileges beyond simple duplication, which can unintentionally grant additional inter-agent access or hook permissions not expected by the operator.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The cron schedule hard-codes the Asia/Shanghai timezone, which is a locale-specific setting. In this manifest there is no indication that the skill is region-specific, user-configurable, or that the locale choice is justified, so it may violate 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
96% confidence
Finding

This code file contains user-facing natural-language strings and documentation entirely in Chinese, including the module docstring and later prompts/messages, but it does not offer any user opt-in or language selection. Under the policy rule, forcing a specific language in user-facing interaction without choice is a natural-language policy violation.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
98% confidence
Finding

The helper run_cmd executes a string with shell=True, which is dangerous because any attacker-controlled content incorporated into the command string can trigger shell metacharacter expansion and arbitrary command execution. In this script it is currently used for an openclaw CLI invocation, but the helper is generic and normalizes unsafe shell execution in a migration tool that processes untrusted package content and modifies the local environment.

Content

Scanner excerpt · migrate.py (reported line 43)May include surrounding context.

python
def info(msg):  print(f"{BLUE}[i]{NC} {msg}")

def run_cmd(cmd):
    result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
    return result.stdout.strip(), result.returncode

# =============================================

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
85% confidence
Finding

Although this call safely avoids shell injection by using a list, it still forwards untrusted cron task definitions from the migration package directly into the openclaw task subsystem. If the downstream openclaw tasks feature executes payloads or privileged actions, importing attacker-supplied jobs can establish persistence or trigger unauthorized actions after installation.

Content

Scanner excerpt · migrate.py (reported line 458)May include surrounding context.

python
continue
        
        task_json = json.dumps(task, ensure_ascii=False)
        result = subprocess.run(
            ["openclaw", "tasks", "add", "--job", task_json],
            capture_output=True, text=True
        )