Back to skill

Security audit

ERCData

Security checks for vulnerabilities and agentic risk

Overview

This skill is purpose-aligned for blockchain data storage, but it under-warns users about irreversible public exposure and encourages risky private-key handling.

Install only if you understand Base mainnet transaction costs and permanence. Use a dedicated minimally funded wallet, avoid passing private keys with --key, store only hashes or pre-encrypted content, and do not treat --private as confidentiality.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/ercdata-cli.py:304
Finding

Wallet Private Key Exposed Through Process Command-Line Arguments

Content
View full analysis

Vulnerability Details

File Location: scripts/ercdata-cli.py:304; usage examples in SKILL.md:15-32
Vulnerability Type: Sensitive credential exposure through process arguments
Risk Level: High

Vulnerable Code

The CLI accepts a wallet private key directly as an argument:

python
parser.add_argument("--key", default=PRIVATE_KEY, help="Private key")

The documented commands encourage users to pass the environment variable through that argument:

bash
uv run {baseDir}/scripts/ercdata-cli.py store \
  --type AI_AGENT_MEMORY \
  --data "memory hash: abc123" \
  --metadata '{"agent":"MyBot","ts":"2026-01-31"}' \
  --key $ERCDATA_KEY --contract $ERCDATA_CONTRACT

Technical Analysis

When $ERCDATA_KEY is expanded as the value of --key, the actual wallet private key becomes part of the Python process argument vector. Command-line arguments can be captured by process inspection utilities, process-monitoring services, audit systems, CI telemetry, diagnostic tools, command wrappers, or improperly configured logs.

Although environment variables also require careful handling, expanding the variable into a command-line argument unnecessarily increases exposure. The affected credential is a signing key for a potentially funded Base wallet and is therefore equivalent to full control of that wallet.

Attack Path

  1. A user follows the documented Quick Start command and supplies --key $ERCDATA_KEY.
  2. The shell expands $ERCDATA_KEY to the plaintext private key before starting the CLI.
  3. The plaintext key appears in the process argument vector.
  4. A local user, monitoring agent, CI logger, diagnostic collector, or other process with access to process metadata records the arguments.
  5. The observer imports the captured private key into another wallet or signing tool.
  6. The attacker signs arbitrary transactions as the affected account, independently of the ERCData CLI.

Exploi ...[truncated 826 chars]

Remediation
View remediation

Remediation Suggestions

  • Remove the --key command-line option so private keys cannot be supplied through the process argument vector.
  • Read the key from a narrowly scoped environment variable only when no safer signer is available.
  • Prefer a protected credential file with restrictive permissions, an operating-system keyring, a hardware wallet, or an external signing service.
  • If interactive use is required, accept the key through a non-echoing prompt or protected standard input rather than a command-line argument.
  • Update every example in SKILL.md to omit --key $ERCDATA_KEY.
  • Use a dedicated, minimally funded wallet with only the contract roles necessary for the intended command.
  • Ensure application, CI, shell, and monitoring logs redact wallet keys and other signing material.
  • Avoid retaining private-key strings longer than necessary in application memory.

T09 · Insecure Skill Coding Practices

Error
Location
scripts/ercdata-cli.py:145
Finding

Access-Controlled “Private” Data Is Published On-Chain in Plaintext

Content
View full analysis

Vulnerability Details

File Location: scripts/ercdata-cli.py:145-153; private-storage example and warning in SKILL.md:20-25,60-64
Vulnerability Type: Plaintext disclosure of sensitive data in public blockchain transaction calldata
Risk Level: High

Vulnerable Code

The CLI encodes user data directly as UTF-8 and submits it to storePrivateData without encryption:

python
def cmd_store(args):
    w3, account = get_web3(args.rpc, args.key)
    contract = get_contract(w3, args.contract)

    data_bytes = args.data.encode("utf-8") if isinstance(args.data, str) else args.data
    meta_bytes = args.metadata.encode("utf-8") if args.metadata else b""

    sig = sign_eip712(w3, account, args.contract, args.type, data_bytes, meta_bytes)

    fn = contract.functions.storePrivateData if args.private else contract.functions.storeData
    tx_hash = fn(args.type, data_bytes, meta_bytes, sig).transact()

The Quick Start presents plaintext secret data as a private-storage example:

bash
uv run {baseDir}/scripts/ercdata-cli.py store \
  --type AI_AGENT_MEMORY \
  --data "secret memory data" \
  --private \
  --key $ERCDATA_KEY --contract $ERCDATA_CONTRACT

The documentation separately acknowledges that raw transaction calldata remains visible:

text
Private entries store the same data on-chain but gate `getData()` access.
Note: raw transaction calldata is still visible on-chain explorers.
For maximum privacy, encrypt data before storing.

Technical Analysis

The --private option selects the contract's storePrivateData function, but it does not provide cryptographic confidentiality. The submitted data_bytes and meta_bytes remain plaintext ABI parameters inside the signed transaction.

Contract-level authorization may prevent unauthorized callers from retrieving the value through getData(), but it cannot hide historical transaction calldata, mempool observations ...[truncated 1952 chars]

Remediation
View remediation

Remediation Suggestions

  • Do not describe storePrivateData as confidential or private storage. Label it explicitly as plaintext, access-controlled storage.
  • Encrypt sensitive data locally before transaction construction using authenticated encryption such as AES-GCM or ChaCha20-Poly1305.
  • Manage encryption keys independently of the blockchain. Do not include plaintext keys, reusable key-encryption material, or secrets in calldata or metadata.
  • For multiple authorized readers, use a reviewed envelope-encryption design in which a random content-encryption key is wrapped separately for each authorized recipient.
  • Prefer storing only a cryptographic hash, commitment, or encrypted content identifier on-chain while retaining sensitive content in an appropriate encrypted storage system.
  • Implement the advertised store-encrypted operation securely or remove it from the usage documentation.
  • Replace the plaintext "secret memory data" example with a hash or clearly non-sensitive demonstration value.
  • Add an explicit interactive warning and confirmation before submitting access-controlled plaintext.
  • Document that metadata, transaction input, mempool traffic, logs, and historical chain data are public and cannot be made private through contract access checks.
  • Treat data already submitted through this mechanism as compromised and rotate any credentials or secrets it contained.
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (8)

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The documentation materially overstates privacy and feature support: it presents 'private' storage as sensitive-data handling while also noting that raw calldata remains public, meaning users may mistakenly place secrets directly on-chain. This mismatch is dangerous in this blockchain context because data disclosure is permanent and irreversible, and unsupported or misleading commands/features can lead operators to rely on protections that do not actually exist.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
83% confidence
Finding

The skill exposes sensitive capabilities through environment-variable use, including a blockchain private key, but does not declare any tool scope or permission boundary. In an agent setting, missing scope metadata can cause the runtime or reviewer to underestimate that the skill may access secrets and initiate signed blockchain actions, increasing the risk of unintended key use or transaction execution.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill omits a prominent warning that storing data creates irreversible, publicly observable blockchain transactions and incurs gas costs. In this context, users may accidentally publish sensitive information or trigger unwanted spending, and unlike a normal storage backend these actions cannot be undone after broadcast.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The API reference describes storePrivateData as offering private storage and says only certain parties can read it, but it does not warn users that blockchain data, calldata, logs, off-chain indexing, node visibility, and future implementation mistakes can still undermine confidentiality. In a skill explicitly designed to store AI data fingerprints and manage private data on-chain, this omission can cause developers to place sensitive material on-chain under a false assumption of privacy, leading to irreversible data exposure or access-control misuse.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The CLI advertises encrypted/private storage with access-list support, but the implemented commands do not provide the documented encrypted-storage workflow or access-list handling. In a blockchain data-management tool, this mismatch can cause users or upstream agents to assume confidentiality protections exist when they do not, leading to accidental disclosure of sensitive data on-chain.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

The read operation decodes and prints retrieved data and metadata directly to stdout without any disclosure warning or output-safety controls. In agent or automated environments, stdout may be logged, forwarded, or exposed to operators, turning an authorized read of sensitive blockchain-backed data into secondary leakage through logs and transcripts.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The store command accepts arbitrary user data for on-chain submission without clearly warning that blockchain writes are durable and typically publicly visible. In this skill context, users may supply AI artifacts, prompts, or sensitive records; absent strong warnings, they can irreversibly publish confidential material and create a permanent audit trail they did not intend.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The info command is described as public-only, but it calls getData directly, which may retrieve private entry contents depending on contract behavior and caller permissions. Even though this function prints only sizes and metadata flags, the direct access path undermines the safety boundary implied by the interface and could expose or mishandle private data if contract semantics change or wrappers are reused incorrectly.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.