Back to skill

Security audit

X-Claw

Security checks for vulnerabilities and agentic risk

Overview

This skill is purpose-aligned with X-Claw wallet and approval operations, but it automatically changes installed OpenClaw gateway code and creates permissive spending policy defaults that users should review before installing.

Install only if you are comfortable with a skill that can move wallet funds, change approval policy, return sensitive management links, and modify/restart your local OpenClaw gateway. Before use, disable or explicitly review gateway auto-patching, inspect the default policy file, set per-operation approvals and low spend limits, and treat API keys, management URLs, and wallet signatures as sensitive.

Vulnerability Patterns
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Tool Hijacking and SpoofingModifies or replaces tools so legitimate-looking calls execute attacker logic
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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 (3)

T07 · Tool Hijacking and Spoofing

Error
Location
scripts/xclaw_agent_skill.py:22
Finding

Automatic Modification and Restart of the Installed OpenClaw Gateway

Content
View full analysis
None: if os.environ.get("XCLAW_OPENCLAW_AUTO_PATCH", "1").strip().lower() in {"0", "false", "no"}: return script_dir = Path(__file__).resolve().parent patcher = script_dir / "openclaw_gateway_patch.py" if not patcher.exists(): return # Best-effort, quiet. Restart is guarded by cooldown+lock inside the patcher. try: subprocess.run(["python3", str(patcher), "--json", "--restart"], text=True, capture_output=True, timeout=20) except Exception: return ``` The patch is invoked from the normal command execution path at `scripts/xclaw_agent_skill.py:486`: ```python try: _maybe_patch_openclaw_gateway() child = subprocess.Popen( cmd, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, start_new_session=True, ) ``` From `scripts/openclaw_gateway_patch.py:1442-1451`: ```python if changed: try: bundle.write_text(patched_text, encoding="utf-8") changed_any = True except Exception as exc: state["lastErrorAt"] = _utc_now() state["lastErrorAtEpoch"] = time.time() state["lastErrorVersion"] = version state["lastError"] = f"write_failed:{bundle}:{exc}" continue ``` Gateway restart logic from `scripts/openclaw_gateway_patch.py:1304-1335`: ```python if shutil.which("systemctl"): try: active = subprocess.run( ["systemctl", "--user", "is-active", "openclaw-gateway.service"], text=True, capture_output=True, timeout=5, ) if active.returncode == 0: ...[truncated 3775 chars]
Remediation
View remediation

T01 · Skill Instruction Hijacking

Error
Location
scripts/openclaw_gateway_patch.py:694
Finding

Synthetic Instruction Injection into the Agent Message Pipeline

Content
View full analysis
[]); const syntheticAllowFrom = Array.from(new Set([ ...(Array.isArray(storeAllowFrom2) ? storeAllowFrom2.map((v) => String(v)) : []), String(callback?.from?.id ?? ""), String(chatId ?? "") ])).filter((v) => !!v); const getFile2 = typeof ctx.getFile === "function" ? ctx.getFile.bind(ctx) : async () => ({}); const syntheticMessage2 = { ...callbackMessage, from: callback.from, text: syntheticText, caption: void 0, caption_entities: void 0, entities: void 0, date: Math.floor(Date.now() / 1000) }; await processMessage( { message: syntheticMessage2, me: ctx.me, getFile: getFile2 }, [], syntheticAllowFrom, { messageIdOverride: `xclaw-transfer-result-${callback.id}` } ); ``` Trade-result routing follows the same pattern: ```javascript const instruction = body?.ok ? "Reply to the user confirming the trade succeeded with tx details." : "Reply to the user confirming the trade failed and provide next steps."; const syntheticText = `[X-CLAW T ...[truncated 4069 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/setup_agent_skill.py:230
Finding

Fresh Installations Enable Spending Without Explicit Approval

Content
View full analysis
None: """Create a safe default local policy file when missing. Policy is required for spend actions (spot swap, transfers) and is enforced by xclaw-agent runtime. """ APP_DIR.mkdir(parents=True, exist_ok=True) _chmod_if_posix(APP_DIR, 0o700) if POLICY_FILE.exists(): # Do not mutate an existing policy; owners may have tightened it. return # NOTE: Slice 06 policy caps are temporarily native-denominated. In practice, this cap is used # as a coarse safety brake for any spend-like action until USD-cap pipeline slices land. # # Defaults are intentionally permissive enough for testnet usage while still being finite. payload = { "paused": False, "chains": { # Enable the default chain to avoid "policy missing" spend failures after install. default_chain: {"chain_enabled": True}, # Hardhat-local is commonly used for local verification; keep enabled when present. "hardhat_local": {"chain_enabled": True}, }, "spend": { # Keep spot swaps usable out-of-the-box. Owners can tighten to require explicit approval. "approval_required": False, "approval_granted": True, # 1000e18 (1,000 "native wei-denominated units") daily cap as a coarse brake. "max_daily_native_wei": "1000000000000000000000", }, } POLICY_FILE.write_text(json.dumps(payload, indent=2) + "\n", encoding="utf-8") _chmod_if_posix(POLICY_FILE, 0o600) ``` The chain is selected from the environment during setup: ```python ensure_default_policy_file(os.environ.get("XCLAW_DEFAULT_CHAIN", "base_sepolia")) ``` ### Technical Analysis ...[truncated 2559 chars]
Remediation
View remediation
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 (39)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

A second description-behavior mismatch indicates the skill performs installer/setup tasks, writes configuration and policy files, creates launchers on PATH, copies files into managed directories, and may patch and restart the gateway. This is materially more powerful than simple runtime operation, and hidden setup behavior can silently weaken spend-approval controls, modify execution paths, or establish persistence on the local machine.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

A second description-behavior mismatch indicates the skill performs installer/setup tasks, writes configuration and policy files, creates launchers on PATH, copies files into managed directories, and may patch and restart the gateway. This is materially more powerful than simple runtime operation, and hidden setup behavior can silently weaken spend-approval controls, modify execution paths, or establish persistence on the local machine.

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
Use this skill to run X-Claw commands safely through `scripts/xclaw_agent_skill.py`.

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/openclaw_gateway_patch.py (reported line 641)May include surrounding context.

python
'\t\t\t\t\tconst chainKey = parts[3];\n'
        f'\t\t\t\t\ttry {{ logger.info({{ subjectId, chainKey, chatId, senderId, isGroup, kind: parts[0] }}, "{MARKER}"); }} catch {{}}\n'
        '\t\t\t\t\tconst skill = cfg?.skills?.entries?.["xclaw-agent"];\n'
        '\t\t\t\t\tconst env = skill?.env ?? {};\n'
        '\t\t\t\t\tconst apiKey = String(skill?.apiKey ?? env?.XCLAW_API_KEY ?? process.env.XCLAW_API_KEY ?? "").trim();\n'
        '\t\t\t\t\t// Reduce perceived latency: best-effort stop spinner while runtime applies canonical clear.\n'
        '\t\t\t\t\ttry { bot.api.answerCallbackQuery(callback.id, { text: action === "r" ? "Denying..." : "Approving...", show_alert: false }); } catch {}\n'

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/openclaw_gateway_patch.py (reported line 1137)May include surrounding context.

python
'\t\t\t\t\tconst chainKey = parts[3];\n'
        f'\t\t\t\t\ttry {{ logger.info({{ subjectId, chainKey, chatId, senderId, isGroup, kind: parts[0] }}, "{MARKER}"); }} catch {{}}\n'
        '\t\t\t\t\tconst skill = cfg?.skills?.entries?.["xclaw-agent"];\n'
        '\t\t\t\t\tconst env = skill?.env ?? {};\n'
        '\t\t\t\t\tconst apiKey = String(skill?.apiKey ?? env?.XCLAW_API_KEY ?? process.env.XCLAW_API_KEY ?? "").trim();\n'
        '\t\t\t\t\t// Reduce perceived latency: best-effort stop spinner while runtime applies canonical clear.\n'
        '\t\t\t\t\ttry { bot.api.answerCallbackQuery(callback.id, { text: action === "r" ? "Denying..." : "Approving...", show_alert: false }); } catch {}\n'

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/openclaw_gateway_patch.py (reported line 1147)May include surrounding context.

python
'\t\t\t\t\tconst chainKey = parts[3];\n'
        f'\t\t\t\t\ttry {{ logger.info({{ subjectId, chainKey, chatId, senderId, isGroup, kind: parts[0] }}, "{MARKER}"); }} catch {{}}\n'
        '\t\t\t\t\tconst skill = cfg?.skills?.entries?.["xclaw-agent"];\n'
        '\t\t\t\t\tconst env = skill?.env ?? {};\n'
        '\t\t\t\t\tconst apiKey = String(skill?.apiKey ?? env?.XCLAW_API_KEY ?? process.env.XCLAW_API_KEY ?? "").trim();\n'
        '\t\t\t\t\t// Reduce perceived latency: best-effort stop spinner while runtime applies canonical clear.\n'
        '\t\t\t\t\ttry { bot.api.answerCallbackQuery(callback.id, { text: action === "r" ? "Denying..." : "Approving...", show_alert: false }); } catch {}\n'

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/openclaw_gateway_patch.py (reported line 1157)May include surrounding context.

python
'\t\t\t\t\tconst chainKey = parts[3];\n'
        f'\t\t\t\t\ttry {{ logger.info({{ subjectId, chainKey, chatId, senderId, isGroup, kind: parts[0] }}, "{MARKER}"); }} catch {{}}\n'
        '\t\t\t\t\tconst skill = cfg?.skills?.entries?.["xclaw-agent"];\n'
        '\t\t\t\t\tconst env = skill?.env ?? {};\n'
        '\t\t\t\t\tconst apiKey = String(skill?.apiKey ?? env?.XCLAW_API_KEY ?? process.env.XCLAW_API_KEY ?? "").trim();\n'
        '\t\t\t\t\t// Reduce perceived latency: best-effort stop spinner while runtime applies canonical clear.\n'
        '\t\t\t\t\ttry { bot.api.answerCallbackQuery(callback.id, { text: action === "r" ? "Denying..." : "Approving...", show_alert: false }); } catch {}\n'

Env Variable Harvesting

High
Category
Data Exfiltration
Confidence
60% confidence
Finding

Code enumerates, copies, or searches environment variables for secrets. Bulk environment access can collect credentials unrelated to the skill's stated purpose.

Content

Scanner excerpt · scripts/setup_agent_skill.py (reported line 282)May include surrounding context.

python
try:
            if os.environ.get("XCLAW_OPENCLAW_AUTO_PATCH", "1").strip().lower() not in {"0", "false", "no"} and PATCHER.exists():
                # Restart is best-effort and guarded by cooldown+lock inside patcher.
                patch_env = dict(os.environ)
                patch_env["OPENCLAW_BIN"] = str(openclaw_bin)
                patch_proc = run([*_python_command(), str(PATCHER), "--json", "--restart"], check=False, env=patch_env)
                gateway_patch = _parse_last_json_line((patch_proc.stdout or "").strip()) or {}

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding

The skill advertises broad operational capabilities involving shell, filesystem, environment variables, and network access, but the manifest does not declare any explicit tool scope or permissions boundary. That creates a confused-deputy risk where a caller may treat the skill as a narrow runtime wrapper while it can actually perform much more powerful local actions, including wallet- and system-adjacent operations.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
80% 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 · SKILL.md (reported line 104)May include surrounding context.

md
- For `approval_pending`:
  - transfer (`xfr_...`): respond briefly that approval is queued; do not paste raw queued transfer text.
  - trade/policy: respond with concise pending status and next step.
  - policy (`ppr_...`): runtime posts Telegram approval prompt with inline buttons when last active channel is Telegram; do not ask the user/model to repost queued policy text.
- Non-Telegram channels (web/Discord/Slack):
  - do not mention Telegram callback instructions,
  - route approval to web management,

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill exposes wallet sends, token transfers, trading, liquidity management, and policy-setting commands, yet the user-facing description does not prominently warn that these actions can be irreversible and financially consequential. In a wallet/agent context, insufficient risk disclosure increases the chance of accidental high-impact user actions, especially when commands are numerous and operationally broad.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The command reference exposes value-transferring and potentially irreversible operations such as trading, liquidity changes, and wallet sends without any adjacent warning about financial loss, slippage, wrong-address risk, or irreversibility. In a wallet/agent skill, omission of these warnings increases the chance that an LLM or user invokes dangerous operations casually or without adequate confirmation context.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

owner-link provides a management URL that is effectively privileged account-management access, yet the reference does not clearly label it as a sensitive secret-equivalent artifact. If echoed into the wrong channel, logs, or untrusted chat context, an attacker could gain management access or trigger privileged actions.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

Exposing wallet-sign-challenge without warning is risky because arbitrary message signing can prove wallet ownership, authorize off-platform actions, or be abused in phishing-style flows. Users and upstream agents may incorrectly treat message signing as harmless when it can have real authentication and authorization consequences.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
80% 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 · references/commands.md (reported line 209)May include surrounding context.

md
- transfer `approval_pending` (`xfr_...`): do not echo `queuedMessage`; send a short "queued for management approval" acknowledgment.
  - trade `approval_pending`: send concise pending-approval acknowledgment; runtime/gateway handles Telegram button delivery.
  - policy `approval_pending` (`ppr_...`): send concise pending-approval acknowledgment; runtime sends Telegram prompt with inline buttons when last active channel is Telegram.
  - do not ask user/model to repost queued policy prompt text for button attachment.
  - fallback override: when `XCLAW_TELEGRAM_APPROVALS_FORCE_MANAGEMENT=1`, route Telegram approvals via management link flow (same as non-Telegram), and do not assume inline buttons are available.
- Non-Telegram conversation (web chat / Slack / Discord / other):
  - do not include Telegram button directives or callback payloads,

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The documentation instructs users to store a live API bearer token in a local plaintext config file but does not warn that the credential is sensitive, long-lived, and should be protected from disclosure. On shared systems, synced home directories, backups, logs, or accidental file sharing, this can expose the token and allow unauthorized use of the X-Claw agent API with the user's privileges.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The script's core behavior is to locate, rewrite, and persistently patch installed OpenClaw gateway bundles outside the local X-Claw runtime boundary described by the skill. That creates a supply-chain and integrity risk because it modifies another installed package's execution path, enabling durable behavior changes that are difficult for users to inspect or attribute.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/openclaw_gateway_patch.py (reported line 200)May include surrounding context.

python
def _read_openclaw_version(openclaw_bin: str, pkg_root: Path | None) -> str | None:
    try:
        proc = subprocess.run([openclaw_bin, "--version"], text=True, capture_output=True, timeout=5)
        if proc.returncode == 0:
            value = (proc.stdout or "").strip()
            if value:

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/openclaw_gateway_patch.py (reported line 253)May include surrounding context.

python
STATE_DIR.mkdir(parents=True, exist_ok=True)
        tmp = STATE_DIR / f".tmp-openclaw-bundle-check-{os.getpid()}.mjs"
        tmp.write_text(js_text, encoding="utf-8")
        proc = subprocess.run([node, "--check", str(tmp)], text=True, capture_output=True, timeout=10)
        ok = proc.returncode == 0
        if not ok:
            err = (proc.stderr or proc.stdout or "").strip()

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The file combines package rewriting with automatic gateway restart capability, which materially exceeds a normal runtime-operations skill and increases blast radius. In the skill context, this is more dangerous because the agent can silently alter installed software and then activate the changes immediately, affecting future approvals and message handling.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/openclaw_gateway_patch.py (reported line 1307)May include surrounding context.

python
# Prefer systemd user service when present.
    if shutil.which("systemctl"):
        try:
            active = subprocess.run(
                ["systemctl", "--user", "is-active", "openclaw-gateway.service"],
                text=True,
                capture_output=True,

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/openclaw_gateway_patch.py (reported line 1314)May include surrounding context.

python
timeout=5,
            )
            if active.returncode == 0:
                subprocess.run(["systemctl", "--user", "restart", "openclaw-gateway.service"], timeout=15)
                state["lastRestartAtEpoch"] = now
                state["lastRestartAt"] = _utc_now()
                _write_json(STATE_FILE, state)

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The gateway is restarted automatically after patching, with no explicit runtime warning to the operator. This can unexpectedly activate modified code, interrupt service, and reduce the chance that an administrator notices unauthorized or unsafe changes before they take effect.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/openclaw_gateway_patch.py (reported line 1326)May include surrounding context.

python
openclaw = _resolve_openclaw_bin()
    if openclaw:
        try:
            proc = subprocess.run([openclaw, "gateway", "restart"], text=True, capture_output=True, timeout=20)
            if proc.returncode == 0:
                state["lastRestartAtEpoch"] = now
                state["lastRestartAt"] = _utc_now()

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The script writes modified bundle contents directly to installed gateway files without any user-facing warning or confirmation at the point of change. Silent persistence of code changes undermines operator awareness and can conceal integrity-impacting modifications, especially in an agent skill expected to perform runtime operations rather than package surgery.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.dangerous_exec, suspicious.env_credential_access

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/openclaw_gateway_patch.py:373

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/openclaw_gateway_patch.py:373