T09 · Insecure Skill Coding Practices
Error
- Location
- SKILL.md:150
- Finding
- Wallet Private Key and Recovery Mnemonic Stored in Plaintext## Vulnerability Details **File Location**: `SKILL.md`, lines 150-164 **Vulnerability Type**: Plaintext storage of wallet credentials **Risk Level**: High ### Vulnerable Code ```python WALLET_FILE = "agent_wallet.json" def get_or_create_wallet(): """Get existing wallet or create new one (ONCE per agent!)""" if os.path.exists(WALLET_FILE): with open(WALLET_FILE, 'r') as f: return json.load(f) # First time only - create new wallet Account.enable_unaudited_hdwallet_features() acct, mnemonic = Account.create_with_mnemonic() wallet = { "address": acct.address, "private_key": acct.key.hex(), "seed_phrase": mnemonic } # Save permanently with open(WALLET_FILE, 'w') as f: json.dump(wallet, f) ``` The same insecure storage pattern is repeated in `SKILL.md` at lines 1045-1059. ### Technical Analysis The Skill writes both the wallet private key and its recovery mnemonic to the predictable relative path `agent_wallet.json`. The data is serialized as unencrypted JSON, and the code does not apply restrictive file permissions, encryption, an operating-system credential store, or a dedicated secret-management mechanism. A mnemonic and private key each provide complete control of the wallet. Storing both credentials together increases exposure without providing a security benefit. The relative path also makes the file likely to reside in an application workspace that may be accessible to other skills, local processes, backup tools, support bundles, or source-control operations. The Skill's declared blockchain functionality requires signing access, but it does not require permanent plaintext storage of two equivalent root credentials. This behavior therefore exceeds the minimum safe privilege and secret-retention requirements. ### Attack Path 1. The user or agent invokes the wallet-creation example. 2. ...[truncated 1060 chars]
- Remediation
- ## Remediation Suggestions - Do not retain the recovery mnemonic after initial wallet provisioning. - Store signing credentials in a platform secret manager, hardware-backed wallet, or encrypted Web3 keystore. - Encrypt credentials with a user-supplied secret that is not stored alongside the encrypted data. - Create credential files atomically with owner-only permissions, such as mode `0600`. - Prevent wallet files from being included in repositories, logs, backups, support bundles, or model context. - Separate transaction construction from signing and require explicit authorization for value-bearing or privilege-granting transactions. - Document a credential-rotation and wallet-migration procedure for suspected exposure.
