Storing agent's temporary private keys in localStorage (client-side)
The app generated an agent private key on the client and persisted it in localStorage. localStorage is readable by any JavaScript in the page, so any XSS or malicious extension could exfiltrate private keys and drain funds.
Description
The app generated an agent private key on the client and persisted it in localStorage. localStorage is readable by any JavaScript running in the page, so any XSS vulnerability or malicious extension could exfiltrate private keys and drain funds or impersonate users.
// src/utils/generateAccount.tsimport { privateKeyToAccount, generatePrivateKey } from "viem/accounts";export const generateAgentAccount = (): Agent => {const privateKey = generatePrivateKey();const { address } = privateKeyToAccount(privateKey);return { privateKey, address: address as `0x${string}` };};
// src/utils/store.ts (persists the whole user object to localStorage)localStorage.setItem(`liqhub_trader.user_${state.user.address}`,JSON.stringify(updatedUser));
Impact
The app stores user private keys in localStorage, which is directly readable by any JavaScript in the page. This makes keys exfiltratable via a single XSS, compromised third-party script, or malicious browser extension.
Full compromise of any wallets generated by the app: an attacker can sign transactions, withdraw funds, and impersonate the user on third-party services.
Recommendation
- Do not store private keys in browser storage.
- If an automated agent is required, do server-side signing: create ephemeral keys on the server in a secure vault (HSM/KMS or at least an encrypted server-side store), and only expose signed transactions or operations via authenticated APIs. Prefer HSM/KMS (AWS KMS, GCP KMS, Azure Key Vault, HashiCorp Vault).
- If client-side ephemeral keys are required, keep them only in memory (never persisted) and use short-lived signatures and authorization.
Ipal Network: Confirmed. The team proposed clearing the key whenever the user disconnects and generating a new one on next login. Zealynx: Fixed. We agree with the proposed solution.