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## 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
## 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## 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
## 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.

Lp3

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.

Missing User Warnings

Medium
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.

Missing User Warnings

Medium
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.

Description-Behavior Mismatch

Medium
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.

Missing User Warnings

Medium
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.

Missing User Warnings

Medium
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.

Intent-Code Divergence

Medium
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.

Static analysis

No suspicious patterns detected.