Back to skill

Security audit

ERC-8004 Identity

Security checks for vulnerabilities and agentic risk

Overview

This skill has a coherent Avalanche identity purpose, but it handles wallet private keys and can trigger irreversible mainnet transactions without enough guardrails, including a deploy bug that can leave users with a paid partial setup.

Review this carefully before installing. Use only a low-funds deployment wallet, avoid storing a valuable private key in a plaintext .env file, verify the target chain and contract constructor arguments, and do not run deploy or metadata/price commands until the missing ValidationRegistry constructor argument and confirmation/dry-run gaps are fixed.

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

Warning
Location
cli.js:139
Finding

Irreversible Partial Mainnet Deployment Caused by Missing Constructor Argument

Content
View full analysis

Vulnerability Details

File Location: cli.js, lines 139-175
Vulnerability Type: Incorrect smart-contract deployment sequencing and constructor invocation
Risk Level: Medium

Vulnerable Code

javascript
// Step 1: Register Identity
if (!deployment.agentId) {
  console.log("1. Registering agent identity...");
  const identity = new ethers.Contract(IDENTITY_REGISTRY, IDENTITY_ABI, wallet);

  const tx = await identity["register()"]({ gasLimit: 200000 });
  console.log("   TX:", tx.hash);
  const receipt = await tx.wait();

  // Parse agent ID from Transfer event
  const transferLog = receipt.logs.find(l =>
    l.topics[0] === ethers.id("Transfer(address,address,uint256)")
  );
  const agentId = parseInt(transferLog.topics[3], 16);

  deployment.agentId = agentId;
  deployment.identityRegistry = IDENTITY_REGISTRY;
  deployment.reputationRegistry = REPUTATION_REGISTRY;
  saveDeployment(deployment);

  console.log("   ✅ Registered! Agent ID:", agentId);
}

// Step 2: Deploy ValidationRegistry
if (!deployment.validationRegistry) {
  console.log("2. Deploying ValidationRegistry...");

  const ValidationRegistry = require("./artifacts/ValidationRegistry.json");
  const factory = new ethers.ContractFactory(
    ValidationRegistry.abi,
    ValidationRegistry.bytecode,
    wallet
  );
  const validationRegistry = await factory.deploy();
  await validationRegistry.waitForDeployment();
}

The bundled artifact at artifacts/ValidationRegistry.json, lines 6-12, declares a required constructor argument:

json
"inputs": [
  {
    "internalType": "address",
    "name": "_identityRegistry",
    "type": "address"
  }
],
"stateMutability": "nonpayable",
"type": "constructor"

Technical Analysis

The CLI invokes factory.deploy() without the required _identityRegistry address. Ethers validates constructor arguments against the ABI, so this call cannot deploy the bundled ValidationRegistry contract successfully.

The failure occurs only af ...[truncated 2041 chars]

Remediation
View remediation

Remediation Suggestions

Pass the required identity-registry address to the constructor:

javascript
const validationRegistry = await factory.deploy(IDENTITY_REGISTRY);
await validationRegistry.waitForDeployment();

Apply the following additional hardening measures:

  1. Add a deployment preflight

    • Inspect each artifact's constructor ABI.
    • Verify that the supplied argument count and types match before sending any transaction.
    • Validate the configured RPC chain ID against the expected chain ID of 43114.
  2. Reorder irreversible operations

    • Deploy and verify prerequisite contracts before registering the identity where protocol semantics permit.
    • Avoid permanent mainnet state changes until all local validation has succeeded.
  3. Simulate before submission

    • Perform gas estimation or transaction simulation for every planned operation.
    • Abort before identity registration if any later deployment cannot be constructed or simulated.
  4. Improve recovery behavior

    • Record explicit deployment phases and transaction hashes.
    • Detect partial deployments and print precise recovery instructions.
    • Do not represent the deployment as retry-safe unless every phase is idempotent.
  5. Add automated integration testing

    • Test the complete deployment sequence against a local EVM or Avalanche-compatible test environment.
    • Assert that all constructor parameters match the bundled artifacts.
    • Verify that identity registration, both deployments, task pricing, and metadata updates complete successfully.
  6. Verify deployed contracts

    • After deployment, confirm runtime bytecode exists at each saved address.
    • Query expected getters such as identityRegistry(), owner(), and agentId() before persisting completion state.
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
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (13)

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 · SKILL.md (reported line 109)May include surrounding context.

PRIVATE_KEY=your_private_key_here

text

Or use keychain:
```bash
export PRIVATE_KEY=$(security find-generic-password -s "YourWallet" -a "YourAccount" -w)

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 · cli.js (reported line 59)May include surrounding context.

js
// Get wallet
function getWallet() {
  require("dotenv").config({ path: path.join(__dirname, ".env") });
  
  const privateKey = process.env.PRIVATE_KEY;
  if (!privateKey) {

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 · cli.js (reported line 63)May include surrounding context.

js
// Get wallet
function getWallet() {
  require("dotenv").config({ path: path.join(__dirname, ".env") });
  
  const privateKey = process.env.PRIVATE_KEY;
  if (!privateKey) {

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 · cli.js (reported line 112)May include surrounding context.

js
fs.writeFileSync(configPath, template);
  console.log("✅ Created config/agent.config.js");
  console.log("📝 Edit the config with your agent details");
  console.log("🔑 Create .env with PRIVATE_KEY=your_key");
}

async function deploy() {

Known Vulnerable Dependency: ws==8.17.1 — 2 advisory(ies): CVE-2026-45736 (ws: Uninitialized memory disclosure); CVE-2026-48779 (ws: Memory exhaustion DoS from tiny fragments and data chunks)

High
Category
Supply Chain
Confidence
98% confidence
Finding

The lockfile pins the transitive dependency ws to version 8.17.1, and the supplied static finding identifies known advisories for uninitialized memory disclosure and memory-exhaustion denial of service in that version. Even though this file is only a lockfile, it governs the exact package version installed, so shipping or deploying with this lockfile would reproduce the vulnerable dependency in environments that use WebSocket functionality through ethers or related code paths.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill explicitly instructs users to place a raw blockchain private key in a local .env file without any warning about secure storage, file permissions, accidental commits, shell history, or host compromise. For a wallet-funded deployment workflow, exposure of that key can directly lead to theft of AVAX and full loss of control over the on-chain identity and deployed contracts.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

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

md
}
  
  const config = loadConfig();
  const rpc = config?.network?.rpc || "https://api.avax.network/ext/bc/C/rpc";
  const provider = new ethers.JsonRpcProvider(rpc);
  return new ethers.Wallet(privateKey, provider);
}

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · cli.js (reported line 68)May include surrounding context.

js
}
  
  const config = loadConfig();
  const rpc = config?.network?.rpc || "https://api.avax.network/ext/bc/C/rpc";
  const provider = new ethers.JsonRpcProvider(rpc);
  return new ethers.Wallet(privateKey, provider);
}

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · cli.js (reported line 103)May include surrounding context.

js
}
  
  const config = loadConfig();
  const rpc = config?.network?.rpc || "https://api.avax.network/ext/bc/C/rpc";
  const provider = new ethers.JsonRpcProvider(rpc);
  return new ethers.Wallet(privateKey, provider);
}

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The deploy flow performs multiple on-chain transactions—identity registration and contract deployments—immediately after the command is invoked, without any explicit confirmation, dry-run summary, or final warning about cost and irreversibility. In a CLI that loads a private key automatically from .env, this increases the chance of accidental fund expenditure or unintended permanent state changes if the command is run in the wrong environment or with unexpected config values.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The set-metadata, set-uri, and set-price commands directly submit transactions that permanently modify on-chain state without any confirmation prompt. Because these commands use the locally loaded private key automatically, a typo, malformed argument, or accidental invocation can result in irreversible metadata corruption, unintended pricing, and unnecessary spending of funds.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The dependency version for dotenv is specified with a caret range, which allows newer minor and patch releases to be installed over time. This creates supply-chain risk because builds are not fully reproducible and a compromised or breaking upstream release could be pulled in without explicit review.

Content

Scanner excerpt · package.json (reported line 23)May include surrounding context.

json
"author": "Eva (@eva_uncensored)",
  "license": "MIT",
  "dependencies": {
    "dotenv": "^16.0.0",
    "ethers": "^6.0.0"
  }
}

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The ethers dependency is also declared with a caret range, permitting automatic installation of later compatible releases. In a blockchain deployment tool, this increases supply-chain and operational risk because unexpected library changes could affect transaction construction, signing, or deployment behavior.

Content

Scanner excerpt · package.json (reported line 24)May include surrounding context.

json
"license": "MIT",
  "dependencies": {
    "dotenv": "^16.0.0",
    "ethers": "^6.0.0"
  }
}

Static analysis

No suspicious patterns detected.