Nuup Custodial Wallet Vulnerability: Stellar Private Keys Stored Unencrypted in Database Despite Encryption Field
A critical security gap has been identified in Nuup's custodial wallet infrastructure. The platform's `Wallet` model includes an `encrypted_secret` field intended to store AES-256-CBC encrypted Stellar private keys, but the actual implementation in `authController.js` stores raw secret keys in plaintext. This means any database breach—including SQL injection, unauthorized database access, or insider threat—would expose every user's private key in readable form.
The vulnerability traces to an incomplete MVP implementation. Partial decryption logic already exists in `eventController.js` and `projectController.js`, attempting AES-256-CBC decryption with silent fallback to plaintext on failure. This pattern reveals that the encryption architecture was designed but never fully wired up. The `WALLET_ENCRYPTION` environment variable, likely intended to control the encryption mechanism, remains unconfigured or ineffective. The code explicitly flags the issue: `const encryptedSecret = keypair.secret(); // ⚠️ NOT actually encrypted`.
For a platform processing escrow deposits and payouts, the implications are severe. A successful attack would grant adversaries control over all affected wallets, enabling fund theft at scale. The plaintext fallback further compounds risk by masking decryption failures—systems may silently operate on unencrypted keys without alerting operators. This represents a single point of failure: the entire key protection scheme depends on database access controls alone, with no defense-in-depth. Implementing the intended AES-256-CBC encryption, ensuring proper key derivation, and removing the plaintext fallback logic are critical remediation steps.