Back to skill

Security audit

Xena Protocol

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly coherent with its phishing-detection purpose, but it needs Review because it uses powerful Gmail and wallet permissions, stores a crypto private key insecurely, and can change inbox state or submit reports automatically.

Install only if you are comfortable granting Gmail read/modify access, sending selected email content to an external LLM, exposing sender-domain metadata to an RPC provider when enabled, and using a testnet wallet whose private key is stored locally in plaintext. Prefer Watcher mode, avoid funding the Reporter wallet beyond tiny testnet amounts, and review the unread-label and auto-report behavior before enabling heartbeat use.

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 (4)

T09 · Insecure Skill Coding Practices

Error
Location
bin/setup.py:43
Finding

Wallet Private Key Stored in Plaintext Without Enforced File Permissions

Content
View full analysis
None: CONFIG_DIR.mkdir(parents=True, exist_ok=True) CONFIG_FILE.write_text(json.dumps(cfg, indent=2) + "\n") ``` ```python def cmd_generate_wallet(_args) -> int: address, pk = generate_wallet() cfg = _load_config() cfg["wallet_address"] = address cfg["wallet_private_key"] = pk # in production: vault; here config _save_config(cfg) _emit({"address": address, "saved_to": str(CONFIG_FILE)}) return 0 ``` ### Technical Analysis Reporter-mode wallet generation stores the Ethereum private key directly in `~/.openclaw/phishing-detection/config.json`. The implementation does not explicitly create the configuration directory with mode `0700` or the file with mode `0600`. Consequently, actual access depends on the process umask, existing directory permissions, backup configuration, and other local environmental controls. The source acknowledges that a production deployment should use a vault, but the active implementation still uses persistent plaintext storage. The private key is a bearer credential: possession is sufficient to authorize transactions independently of this project. Although `RegistryClient` only exposes selected registry operations, this restriction does not protect a private key after it is copied. An attacker can import the key into unrelated Ethereum software and sign arbitrary transactions. ### Attack Path 1. The user selects Reporter mode. 2. `cmd_generate_wallet()` creates a new Ethereum private key. 3. `_save_config()` serializes the key into `config.json` using ambient filesystem permissions. 4. Another local user, compromised process, backup agent, or overly broad file-indexing integration reads the file. 5. The attacker imports the private key int ...[truncated 564 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:186
Finding

Wallet Private Key Exposed Through Command-Line Arguments

Content
View full analysis
\ --amount-wei 100000000000000 \ --private-key ``` ```python def cmd_stake(args) -> int: rpc = os.environ.get("SEPOLIA_RPC") if not rpc: _emit({"error": "SEPOLIA_RPC not set"}) return 2 deployed = args.deployed or DEFAULT_DEPLOYED client = RegistryClient(rpc_url=rpc, deployed_json=deployed) tx = client.stake( recipient=args.recipient, value_wei=args.amount_wei, private_key=args.private_key, ) _emit({"tx": tx, "recipient": args.recipient, "amount_wei": args.amount_wei}) return 0 ``` ```python p = sub.add_parser("stake") p.add_argument("--recipient", required=True) p.add_argument("--amount-wei", type=int, required=True) p.add_argument("--private-key", required=True) p.add_argument("--deployed", type=Path) p.set_defaults(func=cmd_stake) ``` The reporting instructions also prescribe the same pattern: ```text python -m bin.registry_client.report_identity \ --identity-hash \ --domain \ --platform 0 \ --category <0-4> \ --confidence \ --value-wei 10000000000000 \ --private-key ``` ### Technical Analysis The Skill directs the Agent to read the wallet private key and interpolate it into a command-line argument. Process arguments may be visible through process-inspection facilities, shell or terminal history, session tr ...[truncated 1313 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
bin/pipeline.py:193
Finding

Sender-Derived Inbox Metadata Disclosed to an Environment-Controlled RPC Endpoint

Content
View full analysis
0: reasons.append("registry_identity_hit") score = max(score, 90) except Exception: pass try: dom_count = self.registry.domain_report_count(email.from_domain) if dom_count > DOMAIN_HIT_THRESHOLD: reasons.append("registry_domain_hit") score = max(score, 75) except Exception: pass ``` ```python # Optional registry (Watcher mode can skip if no RPC is set) registry = None rpc = os.environ.get("SEPOLIA_RPC") if rpc and deployed_path.exists(): try: registry = RegistryClient(rpc_url=rpc, deployed_json=deployed_path) except Exception as exc: print(json.dumps({"warning": f"registry unavailable: {exc}"}), file=__import__("sys").stderr) ``` ```python def is_reported(self, identity_hash: bytes) -> tuple[bool, int]: return self._contract.functions.isReported(identity_hash).call() def domain_report_count(self, domain: str) -> int: return self._contract.functions.domainReportCount(domain).call() ``` The identifier transformation is deterministic: ```python def hash_identifier(identifier: str) -> bytes: """Client-side keccak256 of a normalized identifier (lowercased).""" normalized = identifier.strip().lower().encode("utf-8") return Web3.keccak(normalized) ``` ### Technical Analysis When `SEPOLIA_RPC` is configured, every processed message can trigger external registry calls containing: - An unsalted, deterministic Keccak-256 hash of the complete sender address. - The sender's domain in ...[truncated 1776 chars]
Remediation
View remediation

other

Warning
Location
SKILL.md:228
Finding

Sensitive Email Content Routed to an External LLM Without a Dedicated Privacy Control

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • YARA SignaturesMalware Match, Webshell Match, Cryptominer Match
Findings (60)

YARA rule 'ransomware_behavior': Ransomware-like patterns (mass encryption, ransom notes) [malware]

Critical
Category
YARA Match
Confidence
80% confidence
Finding

YARA rule matched a known malware signature (reverse shell, backdoor, ransomware, C2 framework, or info stealer).

Content

Scanner excerpt · bin/trainer.py (reported line 53)May include surrounding context.

python
pple ID was used to sign in on a new iPhone. If this was not you please verify your account immediately.",
    "Gmail storage full. Click to upgrade or your messages will be deleted in 24 hours.",
    "LinkedIn connection request pending. Please log in to view and approve.",
    "Your FedEx package delivery failed. Pay the customs fee to reschedule delivery.",
    "IRS notice: you owe back taxes. Pay immediately with bitcoin or gift cards to avoid arrest warrant.",
    "Your Coinbase wallet will be frozen unless you verify ownership. Provide your seed phrase within the hour.",
    "Romance match waiting for you. Beautiful woman looking for a serious relationship. Click to see her photos.",
    "Please process the attached invoice urgently. The vendor changed their bank account. Wire to the new SWIFT code.",
    "Your DocuSign document is ready. Review and sign the attached PDF to complete the transaction.",
    "Urgent: we need you to buy 5000 dollars in Amazon gift cards and email the

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The concise description does not adequately prepare users for environment diagnostics, blockchain wallet creation, and private-key handling as part of normal setup. That under-disclosure matters because the skill processes sensitive email content and introduces cryptographic secrets and external transactions.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The concise description does not adequately prepare users for environment diagnostics, blockchain wallet creation, and private-key handling as part of normal setup. That under-disclosure matters because the skill processes sensitive email content and introduces cryptographic secrets and external transactions.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The concise description does not adequately prepare users for environment diagnostics, blockchain wallet creation, and private-key handling as part of normal setup. That under-disclosure matters because the skill processes sensitive email content and introduces cryptographic secrets and external transactions.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

The concise description does not adequately prepare users for environment diagnostics, blockchain wallet creation, and private-key handling as part of normal setup. That under-disclosure matters because the skill processes sensitive email content and introduces cryptographic secrets and external transactions.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The concise description does not adequately prepare users for environment diagnostics, blockchain wallet creation, and private-key handling as part of normal setup. That under-disclosure matters because the skill processes sensitive email content and introduces cryptographic secrets and external transactions.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The concise description does not adequately prepare users for environment diagnostics, blockchain wallet creation, and private-key handling as part of normal setup. That under-disclosure matters because the skill processes sensitive email content and introduces cryptographic secrets and external transactions.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

The concise description does not adequately prepare users for environment diagnostics, blockchain wallet creation, and private-key handling as part of normal setup. That under-disclosure matters because the skill processes sensitive email content and introduces cryptographic secrets and external transactions.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding

The concise description does not adequately prepare users for environment diagnostics, blockchain wallet creation, and private-key handling as part of normal setup. That under-disclosure matters because the skill processes sensitive email content and introduces cryptographic secrets and external transactions.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The concise description does not adequately prepare users for environment diagnostics, blockchain wallet creation, and private-key handling as part of normal setup. That under-disclosure matters because the skill processes sensitive email content and introduces cryptographic secrets and external transactions.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The concise description does not adequately prepare users for environment diagnostics, blockchain wallet creation, and private-key handling as part of normal setup. That under-disclosure matters because the skill processes sensitive email content and introduces cryptographic secrets and external transactions.

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 215)May include surrounding context.

md
and will use `bin/gog_client.py` to list unread messages, call

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

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

Content

Scanner excerpt · bin/gog_client.py (reported line 8)May include surrounding context.

python
Prerequisites on the user's machine (via OpenClaw):
    brew install steipete/tap/gogcli
    gog auth credentials ~/path/to/client_secret.json
    gog auth add you@gmail.com --services gmail
"""

Missing User Warnings

High
Category
Not specified by scanner
Confidence
99% confidence
Finding

cmd_generate_wallet stores the generated private key directly in ~/.openclaw/phishing-detection/config.json in plaintext. Any local compromise, overly broad file permissions, backups, sync tools, or other software reading that file can exfiltrate the key and take control of the associated wallet funds or identity.

Content

No source excerpt is available for this finding.

Missing User Warnings

High
Category
Not specified by scanner
Confidence
97% confidence
Finding

The stake command performs an on-chain transaction using a supplied private key with no confirmation, preview, or secondary approval in this code path. In a skill controlled by an LLM-driven wizard, this increases the risk of unintended fund movement or socially engineered transactions if the surrounding flow misleads the user or passes incorrect parameters.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: web3==7.8.0 — 2 advisory(ies): CVE-2026-40072 (web3.py: SSRF via CCIP Read (EIP-3668) OffchainLookup URL handling); CVE-2026-40072 (web3.py: SSRF via CCIP Read (EIP-3668) OffchainLookup URL handling)

High
Category
Supply Chain
Confidence
97% confidence
Finding

The pinned dependency web3==7.8.0 is reported as affected by an SSRF issue in CCIP Read / OffchainLookup URL handling. In a skill that interacts with Ethereum and may process attacker-influenced on-chain responses, this is especially relevant because malicious contracts or responses could cause the application to make unintended outbound requests to internal or sensitive network targets.

Content

No source excerpt is available for this finding.

Known Vulnerable Dependency: pytest==8.2.0 — 2 advisory(ies): CVE-2025-71176 (pytest has vulnerable tmpdir handling); CVE-2025-71176 (pytest has vulnerable tmpdir handling)

High
Category
Supply Chain
Confidence
80% confidence
Finding

Dependency has known vulnerabilities (CVEs). Using packages with unpatched security flaws exposes the environment to known exploits.

Content

No source excerpt is available for this finding.

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 · tests/test_setup_cli.py (reported line 36)May include surrounding context.

python
def test_save_mode_writes_config(tmp_path):
    import os
    env = {**os.environ, "HOME": str(tmp_path)}
    r = _invoke("save-mode", "--mode", "watcher", "--gmail-account", "me@gmail.com", env=env)
    assert r.returncode == 0
    cfg = json.loads((tmp_path / ".openclaw" / "phishing-detection" / "config.json").read_text())

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 · tests/test_setup_cli.py (reported line 46)May include surrounding context.

python
def test_save_mode_writes_config(tmp_path):
    import os
    env = {**os.environ, "HOME": str(tmp_path)}
    r = _invoke("save-mode", "--mode", "watcher", "--gmail-account", "me@gmail.com", env=env)
    assert r.returncode == 0
    cfg = json.loads((tmp_path / ".openclaw" / "phishing-detection" / "config.json").read_text())

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 · tests/test_setup_cli.py (reported line 55)May include surrounding context.

python
def test_save_mode_writes_config(tmp_path):
    import os
    env = {**os.environ, "HOME": str(tmp_path)}
    r = _invoke("save-mode", "--mode", "watcher", "--gmail-account", "me@gmail.com", env=env)
    assert r.returncode == 0
    cfg = json.loads((tmp_path / ".openclaw" / "phishing-detection" / "config.json").read_text())

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 · tests/test_setup_cli.py (reported line 71)May include surrounding context.

python
def test_save_mode_writes_config(tmp_path):
    import os
    env = {**os.environ, "HOME": str(tmp_path)}
    r = _invoke("save-mode", "--mode", "watcher", "--gmail-account", "me@gmail.com", env=env)
    assert r.returncode == 0
    cfg = json.loads((tmp_path / ".openclaw" / "phishing-detection" / "config.json").read_text())

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 · tests/test_setup_cli.py (reported line 92)May include surrounding context.

python
def test_save_mode_writes_config(tmp_path):
    import os
    env = {**os.environ, "HOME": str(tmp_path)}
    r = _invoke("save-mode", "--mode", "watcher", "--gmail-account", "me@gmail.com", env=env)
    assert r.returncode == 0
    cfg = json.loads((tmp_path / ".openclaw" / "phishing-detection" / "config.json").read_text())

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The heartbeat performs autonomous Gmail search/retrieval and also includes a state-changing mailbox operation, but this markdown does not present an explicit user-facing warning or consent boundary for those actions. In a background scheduler context, silent access to inbox contents combined with automatic modification of message state increases privacy and integrity risk, especially if detections are wrong or the skill behavior is not fully understood by the user.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The heartbeat instructs the agent to remove the Gmail UNREAD label after processing, which is a state-changing action not clearly necessary for passive scanning and exceeds the user-facing description of scanning/reporting. This can alter the user's mailbox state, hide messages from normal unread workflows, and cause loss of visibility into potentially important or misclassified emails.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The README explicitly states that the agent wallet private key is stored in ~/.openclaw/phishing-detection/config.json, which creates a sensitive-secret-at-rest risk if that file is readable by other local users, included in backups, or exfiltrated by malware. In this skill's context, the secret authorizes blockchain transactions, so compromise of the file could let an attacker impersonate the reporter account, drain the small staked balance, or submit fraudulent on-chain reports tied to the user's identity.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.