xenodia

Security checks across malware telemetry and agentic risk

Overview

This appears to be a real Xenodia gateway helper, but it asks the agent to handle and persist powerful wallet and API credentials in risky ways.

Install only if you trust Xenodia and are comfortable giving the agent wallet-backed account authority. Use a dedicated low-value wallet or tightly scoped CDP credentials, avoid saving secrets in ~/.zshrc, verify XENODIA_BASE_URL before running commands, keep generated API keys out of logs and transcripts, and rotate any secrets that were already printed or stored.

SkillSpector

By NVIDIA
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (20)

Tainted flow: 'XENODIA_BASE_URL' from os.environ.get (line 53, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
signature = await _sign_message(cdp, account, message)

    try:
        resp = requests.post(
            f"{XENODIA_BASE_URL}/v1/auth/verify",
            json={"challenge_id": challenge_id, "signature": signature}, timeout=10
        )
Confidence
88% confidence
Finding
resp = requests.post( f"{XENODIA_BASE_URL}/v1/auth/verify", json={"challenge_id": challenge_id, "signature": signature}, timeout=10 )

Tainted flow: 'XENODIA_BASE_URL' from os.environ.get (line 53, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Content
async with make_cdp_client() as cdp:
                account = await _get_or_create_account(cdp)
                access_token = (await _login(cdp, account))["access_token"]
                resp = requests.get(f"{XENODIA_BASE_URL}/v1/me/api-keys", headers={"Authorization": f"Bearer {access_token}"})
                data = resp.json().get("data")
                if data and data.get("token"):
                    print(data["token"])
Confidence
97% confidence
Finding
resp = requests.get(f"{XENODIA_BASE_URL}/v1/me/api-keys", headers={"Authorization": f"Bearer {access_token}"})

Tainted flow: 'XENODIA_BASE_URL' from os.environ.get (line 53, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
if data and data.get("token"):
                    print(data["token"])
                else:
                    resp = requests.post(f"{XENODIA_BASE_URL}/v1/me/api-keys", headers={"Authorization": f"Bearer {access_token}"})
                    print(resp.json()["data"]["token"])
        run_async(_run())
Confidence
98% confidence
Finding
resp = requests.post(f"{XENODIA_BASE_URL}/v1/me/api-keys", headers={"Authorization": f"Bearer {access_token}"})

Tainted flow: 'XENODIA_BASE_URL' from os.environ.get (line 20, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
def login(acc: Account) -> str:
    try:
        resp = requests.post(
            f"{XENODIA_BASE_URL}/v1/auth/challenge",
            json={"wallet_address": acc.address}, timeout=10
        )
Confidence
84% confidence
Finding
resp = requests.post( f"{XENODIA_BASE_URL}/v1/auth/challenge", json={"wallet_address": acc.address}, timeout=10 )

Tainted flow: 'XENODIA_BASE_URL' from os.environ.get (line 20, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
signable_message = encode_defunct(text=data["message"])
        signature = acc.sign_message(signable_message).signature.hex()

        resp = requests.post(
            f"{XENODIA_BASE_URL}/v1/auth/verify",
            json={"challenge_id": data["challenge_id"], "signature": signature}, timeout=10
        )
Confidence
86% confidence
Finding
resp = requests.post( f"{XENODIA_BASE_URL}/v1/auth/verify", json={"challenge_id": data["challenge_id"], "signature": signature}, timeout=10 )

Tainted flow: 'XENODIA_BASE_URL' from os.environ.get (line 20, credential/environment) → requests.get (network output)

Critical
Category
Data Flow
Content
access_token = login(acc)["access_token"]
        
        # Try to get existing key
        resp = requests.get(f"{XENODIA_BASE_URL}/v1/me/api-keys", headers={"Authorization": f"Bearer {access_token}"})
        data = resp.json().get("data")
        if data and data.get("token"):
            print(data["token"])
Confidence
92% confidence
Finding
resp = requests.get(f"{XENODIA_BASE_URL}/v1/me/api-keys", headers={"Authorization": f"Bearer {access_token}"})

Tainted flow: 'XENODIA_BASE_URL' from os.environ.get (line 20, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
print(data["token"])
        else:
            # Generate a new one
            resp = requests.post(f"{XENODIA_BASE_URL}/v1/me/api-keys", headers={"Authorization": f"Bearer {access_token}"})
            print(resp.json()["data"]["token"])
    elif cmd == "chat":
        if len(args) < 3:
Confidence
93% confidence
Finding
resp = requests.post(f"{XENODIA_BASE_URL}/v1/me/api-keys", headers={"Authorization": f"Bearer {access_token}"})

Context-Inappropriate Capability

Medium
Confidence
97% confidence
Finding
The documentation directs the agent to append highly sensitive third-party credentials to ~/.zshrc for automatic reuse. Persisting long-lived secrets in a shell startup file broadens exposure to other local processes, accidental disclosure, backups, terminal debugging, and future sessions without clear necessity or user-risk disclosure.

Context-Inappropriate Capability

Medium
Confidence
84% confidence
Finding
The skill expands from gateway usage into modifying the owner's local OpenClaw configuration, including inserting generated API credentials. That broadens the trust boundary from service interaction to local configuration tampering, increasing the chance of unintended provider switching, credential sprawl, and lockout if the configuration is changed incorrectly.

Description-Behavior Mismatch

Medium
Confidence
99% confidence
Finding
The file adds API key management even though the declared scope covers wallet authentication, balance/model checks, provider switching, and chat usage. That scope expansion is security-relevant because it introduces credential lifecycle capabilities users would not reasonably expect from this skill.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
The skill can create persistent Xenodia API credentials, which is a stronger and longer-lived privilege than transient wallet-auth access. In this context, that is more dangerous because the stated purpose does not require durable credential issuance, so users may unknowingly grant a capability that survives beyond the current session.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The file implements API-key retrieval and creation even though the stated skill scope centers on wallet authentication, balance/model queries, and provider switching. Hidden credential-management capability is security-relevant because it expands privileges and attack surface beyond what a reviewer or operator would reasonably expect.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The code can create long-lived API credentials despite the skill being framed around ephemeral wallet-based auth. That is dangerous because durable credentials are easier to exfiltrate, reuse, and persist after initial compromise than short-lived access tokens.

Intent-Code Divergence

Low
Confidence
91% confidence
Finding
The help text omits the supported get-api-key command, making the credential-management functionality less visible to users and reviewers. In security-sensitive tooling, undocumented privileged behavior is a meaningful risk because it impairs informed consent, auditing, and review.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
The instructions tell the agent to persist secrets to ~/.zshrc without an adequate privacy/security warning. Users may not realize this creates durable exposure of CDP credentials and wallet secrets across sessions and tools, making credential theft or accidental disclosure more likely.

Missing User Warnings

Medium
Confidence
98% confidence
Finding
The get-api-key path prints a reusable secret directly to stdout without warning, masking, or secure handling. In agent and CLI environments, stdout is often logged, captured in transcripts, or forwarded to orchestrators, making accidental credential disclosure likely.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The client writes the wallet private key to disk in plaintext in the script directory without setting restrictive permissions or clearly warning the user. If the filesystem is accessible to other local users, backups, or adjacent processes, compromise of this file directly compromises the wallet identity.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
Printing the access token directly to stdout can leak it into shell history, logs, terminal recordings, or calling processes. While intended for SDK integration, the absence of a warning or safer handoff mechanism increases accidental credential exposure risk.

Missing User Warnings

High
Confidence
97% confidence
Finding
The get-api-key command retrieves or creates an API key and prints it directly to stdout. Because API keys are typically long-lived and broadly reusable, exposing them this way can lead to durable account compromise via logs, shell capture, CI output, or untrusted wrapper processes.

Ssd 3

High
Confidence
99% confidence
Finding
This is the strongest issue in the file: the skill explicitly instructs persistence of CDP API and wallet secrets into a shell startup file for automatic reuse. These are highly sensitive credentials tied to wallet-backed authentication, so durable plaintext storage in ~/.zshrc significantly raises the blast radius of local compromise, account takeover, and secret leakage.

VirusTotal

66/66 vendors flagged this skill as clean.

View on VirusTotal