T09 · Insecure Skill Coding Practices
Error
- Location
- lib/wallet.ts:11
- Finding
- Wallet Mnemonic Loading and Private-Key Encapsulation Bypass<![CDATA[ ## Vulnerability Details **File Location**: `lib/wallet.ts:11-14` and `lib/wallet.ts:49-58` **Vulnerability Type**: Direct access to wallet recovery material and private SDK state **Risk Level**: High ### Complete Vulnerable Code ```ts const mnemonicPath = join(config.walletDataDir, 'mnemonic.txt'); const mnemonic = existsSync(mnemonicPath) ? readFileSync(mnemonicPath, 'utf-8').trim() : undefined; ``` ```ts // Access the private key from Sphere's internal _identity field. // The public `sphere.identity` getter strips privateKey, but the // underlying TypeScript-private `_identity` stores a FullIdentity // which includes `privateKey: string`. export function getPrivateKeyHex(sphere: Sphere): string { const fullIdentity = (sphere as any)._identity; if (!fullIdentity?.privateKey) { throw new Error('No wallet identity or private key not accessible'); } return fullIdentity.privateKey; } ``` ### Technical Analysis The Skill directly reads the wallet recovery mnemonic from `mnemonic.txt` into its Node.js process. It then deliberately bypasses the Sphere SDK's public interface by casting the object to `any` and accessing the internal `_identity` field. The comments explicitly acknowledge that the public `sphere.identity` getter removes the private key. Accessing `_identity` therefore circumvents an intentional encapsulation boundary designed to prevent consumers from obtaining raw private-key material. Although the private key is subsequently used locally to sign marketplace requests and is not directly transmitted by the reviewed code, both the mnemonic and private key become accessible within the same process as all loaded dependencies. Any compromised dependency, runtime instrumentation, malicious future modification, diagnostic dump, or unintended logging path could consequently expose wallet secrets. ### Attack Path 1. A user invokes an authenticated command such as `scripts/profile.ts`, `scripts/intent.ts`, or `scripts/register.t ...[truncated 1287 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Remove direct filesystem access to `mnemonic.txt` from the Skill. 2. Remove `getPrivateKeyHex()`, the `as any` cast, and all access to the SDK's `_identity` property. 3. Expose a signing operation through the Unicity wallet plugin, such as a narrowly scoped `signMarketplaceRequest(payload)` API, so private-key material never leaves the wallet boundary. 4. Where possible, use OS-backed or hardware-backed key storage and require signing confirmation for sensitive operations. 5. Use a domain-separated signing format that binds the signature to: - The marketplace origin. - HTTP method. - Request path. - Request body. - Timestamp and nonce. 6. Ensure secrets are never included in logs, thrown errors, telemetry, crash dumps, or debug output. 7. Run authenticated marketplace operations in a least-privileged process with only access to the wallet signing interface, not the wallet recovery files. 8. Add tests that fail if application code accesses `mnemonic.txt`, `_identity`, or raw private-key fields. ]]>
