Back to skill

Security audit

zeruai

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly does what it says, but its read path can fetch arbitrary on-chain URLs and it handles funded wallet keys and live on-chain writes with limited safety controls.

Review carefully before installing. Use a dedicated low-balance wallet key, prefer Base Sepolia for testing, avoid placing a primary funded key in plaintext config, and be aware that reading arbitrary agent IDs may cause the runtime to request URLs chosen by other registry participants. Treat register, set-metadata, and unset-wallet as live on-chain actions that can cost funds or change public agent state.

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

T09 · Insecure Skill Coding Practices

Error
Location
lib/get-agent.js:13
Finding
Unrestricted Fetch of Attacker-Controlled On-Chain Agent URI Enables SSRF## Vulnerability Details **File Location**: `lib/get-agent.js:13-29` **Vulnerability Type**: Server-Side Request Forgery (SSRF) **Risk Level**: High ### Vulnerable Code ```js const [owner, agentURI, wallet] = await Promise.all([ registry.ownerOf(id), registry.tokenURI(id), registry.getAgentWallet(id), ]); const ZERO = "0x0000000000000000000000000000000000000000"; const result = { owner, agentURI, agentWallet: wallet === ZERO ? null : wallet, }; // Try to fetch and parse the agentURI if (agentURI && agentURI.startsWith("http")) { try { const res = await fetch(agentURI); if (res.ok) result.parsedJson = (await res.json()); } catch { // skip — optional } } ``` ### Technical Analysis The `agentURI` value is obtained from an on-chain `tokenURI` field that an agent registrant can control. `getAgent()` automatically performs a server-side request to this value whenever it starts with `http`. The prefix check is not an effective security boundary. It permits both HTTP and HTTPS and does not: - Reject loopback, private, link-local, multicast, or reserved IP ranges. - Resolve and validate hostnames against prohibited address ranges. - Restrict requests to trusted hosts. - Revalidate destinations after HTTP redirects. - Enforce connection or response timeouts. - Limit response size before JSON parsing. Although the request does not directly transmit the configured `PRIVATE_KEY`, it allows an attacker to make the Skill runtime access network resources that are not directly reachable by the attacker. Automatic metadata retrieval is not necessary to return the on-chain owner, wallet, and URI fields, so this behavior exceeds the minimum network privileges needed for the core read operation. ### Attack Path 1. An attacker registers or controls an agent record. 2. The attacker sets its on-chain `tokenURI` to an internal target, loopback endpoint, cloud metadata endpoint, or attacker-controlled ...[truncated 1113 chars]
Remediation
## Remediation Suggestions 1. Make remote `agentURI` retrieval explicitly opt-in. By default, return the URI without fetching it. 2. Permit only the `https:` protocol unless HTTP support is strictly required. 3. Resolve the destination hostname and reject all loopback, private, link-local, multicast, unspecified, and reserved IPv4 and IPv6 addresses. 4. Disable automatic redirects or validate the protocol, hostname, resolved addresses, and port at every redirect hop. 5. Prefer an allowlist of trusted metadata hosts where compatible with the registry design. 6. Block sensitive ports and reject URLs containing credentials. 7. Apply strict connection and overall request timeouts using an abort signal. 8. Stream responses with a conservative maximum byte limit before parsing JSON. 9. Validate the response `Content-Type` and parsed document schema. 10. Consider retrieving metadata through an isolated proxy with restricted egress and no access to internal networks or cloud metadata services.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (21)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The skill description says it can 'manage wallets,' but the documented commands only support unsetting an agent wallet, not setting or rotating one. Overstated capability is a trust and safety issue because operators may assume broader wallet-management support and invoke the skill under false expectations, especially around identity and account administration.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The skill description says it can 'manage wallets,' but the documented commands only support unsetting an agent wallet, not setting or rotating one. Overstated capability is a trust and safety issue because operators may assume broader wallet-management support and invoke the skill under false expectations, especially around identity and account administration.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The skill description says it can 'manage wallets,' but the documented commands only support unsetting an agent wallet, not setting or rotating one. Overstated capability is a trust and safety issue because operators may assume broader wallet-management support and invoke the skill under false expectations, especially around identity and account administration.

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill requires access to sensitive environment variables and network connectivity, but it does not declare explicit tool scope or permissions. This weakens least-privilege controls and can allow broader execution than users or the platform may expect, especially because the skill handles a live PRIVATE_KEY and performs on-chain and off-chain requests.

External Transmission

Medium
Category
Data Exfiltration
Content
"services": [
    {
      "name": "MCP",
      "endpoint": "https://api.dataanalyst.ai/mcp",
      "version": "2025-06-18",
      "mcpTools": ["analyze_wallet", "trace_transactions", "detect_anomalies"],
      "capabilities": []
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

External Transmission

Medium
Category
Data Exfiltration
Content
"services": [
    {
      "name": "MCP",
      "endpoint": "https://api.dataanalyst.ai/mcp",
      "version": "2025-06-18",
      "mcpTools": ["analyze_wallet", "trace_transactions", "detect_anomalies"],
      "capabilities": []
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The registration flow explicitly says it creates a hosted JSON document via an Agent URI API before minting, but the documentation does not clearly warn users that their agent metadata is transmitted to an external service. That omission matters because the metadata can include identifying details, service endpoints, and wallet-related information that users may assume stays local until written on-chain.

Session Persistence

Medium
Category
Rogue Agent
Content
```

**Steps to register:**
1. Create a JSON file following the structure above (e.g. `agent.json`)
2. Run: `npx tsx {baseDir}/scripts/zeru.ts register --json agent.json`

The SDK automatically adds `type`, `registrations` (with `agentId: 0` placeholder), and defaults for missing optional fields. After minting, it updates the document with the real `agentId`.
Confidence
60% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding
npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The setup instructions tell users to place a funded private key into configuration but do not prominently warn about secret handling, least privilege, or the risk of committing the file to source control. Because this skill performs blockchain writes, compromise of that key can directly lead to financial loss and unauthorized on-chain actions.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
The function is documented and named as an on-chain reader, but it also performs an unbounded HTTP fetch to a URI controlled by on-chain data. This creates an SSRF and privacy risk: a crafted agentURI can trigger requests to attacker-chosen endpoints, leak the caller's IP/network location, and potentially access internal resources depending on where this code runs.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
The manifest describes using the skill to register agents, check fees, read agent info, set metadata, and manage agent wallets. This index also exports agent discovery/search and reputation retrieval functions, which are additional capabilities not mentioned in the manifest description and broaden the skill beyond the stated operational scope.

Rp1

Medium
Category
MCP Rug Pull
Confidence
95% confidence
Finding
The shebang uses `#!/usr/bin/env npx tsx`, which allows `npx` to resolve and execute whatever `tsx` version is available at runtime rather than a pinned, vetted dependency. In a security-sensitive skill that manages blockchain registrations and uses a private key for write operations, this creates a supply-chain risk where a malicious or compromised package version could execute arbitrary code and exfiltrate secrets.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The `unset-wallet` command performs a destructive on-chain action immediately after argument parsing, with no confirmation prompt, dry-run, or explicit warning about permanence and impact. In the context of an identity-registry skill controlling live on-chain agent state, a mistaken invocation or agent misuse could irreversibly disrupt wallet associations and operational access.

Intent-Code Divergence

Low
Confidence
94% confidence
Finding
The doc comment frames the function as reading on-chain data and optionally parsing the agentURI JSON, but the code implements that parsing by making an external HTTP request to the URL stored on-chain. This is a meaningful intent difference because the comment omits the off-chain network side effect while presenting the function as an on-chain read operation.

Intent-Code Divergence

Low
Confidence
97% confidence
Finding
The CLI documents registration as reporting details of the newly registered agent, but `console.log(` Name: ${name}`)` uses a variable that is not defined in `cmdRegister`. In practice this contradicts the apparent intent of the surrounding status output and would fail or misreport at the end of a successful registration flow.

Static analysis

No suspicious patterns detected.