--- name: multiversx-dapp-audit description: Audit frontend dApp components for security vulnerabilities in wallet integration and transaction handling. Use when reviewing React/TypeScript dApps using sdk-dapp, or assessing client-side security. --- # MultiversX dApp Auditor Audit the frontend components of MultiversX applications built with `@multiversx/sdk-dapp`. This skill focuses on client-side security, transaction construction, and wallet integration vulnerabilities. ## When to Use - Reviewing React/TypeScript dApp code - Auditing wallet connection implementations - Assessing transaction signing security - Checking for XSS and data exposure vulnerabilities - Validating frontend-backend security boundaries ## 1. Transaction Construction Security ### The Threat Model The frontend constructs transaction payloads that users sign. Vulnerabilities here can trick users into signing malicious transactions. ### Payload Manipulation ```typescript // VULNERABLE: User input directly in transaction data const sendTransaction = async (userInput: string) => { const tx = new Transaction({ receiver: Address.newFromBech32(recipientAddress), data: Buffer.from(userInput), // Attacker controls data! // ... }); await signAndSend(tx); }; // SECURE: Validate and sanitize all inputs const sendTransaction = async (functionName: string, args: string[]) => { // Whitelist allowed functions const allowedFunctions = ['stake', 'unstake', 'claim']; if (!allowedFunctions.includes(functionName)) { throw new Error('Invalid function'); } // Validate arguments const sanitizedArgs = args.map(arg => validateArgument(arg)); const tx = new Transaction({ receiver: contractAddress, data: Buffer.from(`${functionName}@${sanitizedArgs.join('@')}`), // ... }); await signAndSend(tx); }; ``` ### Critical Checks | Check | Risk | Mitigation | |-------|------|------------| | Receiver address validation | Funds sent to wrong address | Validate against known addresses | | Data payload construction | Malicious function calls | Whitelist allowed operations | | Amount validation | Incorrect value transfers | Confirm amounts with user | | Gas limit manipulation | Transaction failures | Use appropriate limits | ## 2. Signing Security ### Blind Signing Risks Users may sign transactions without understanding the content: ```typescript // DANGEROUS: Signing opaque data const signMessage = async (data: string) => { const hash = keccak256(data); return await wallet.signMessage(hash); // User sees only hash! }; // SECURE: Show clear message to user const signMessage = async (message: string) => { // Display message to user before signing const confirmed = await showConfirmationDialog({ title: 'Sign Message', content: `You are signing: "${message}"`, warning: 'Only sign messages you understand' }); if (!confirmed) throw new Error('User rejected'); return await wallet.signMessage(message); }; ``` ### Transaction Preview Requirements Before signing, users should see: - Recipient address (with verification if known) - Amount being transferred - Token type (EGLD, ESDT, NFT) - Function being called (if smart contract interaction) - Gas cost estimate ## 3. Sensitive Data Handling ### Private Key Security ```typescript // CRITICAL VULNERABILITY: Never do this localStorage.setItem('privateKey', wallet.privateKey); localStorage.setItem('mnemonic', wallet.mnemonic); sessionStorage.setItem('seed', wallet.seed); // Check for these patterns in code review: // - Any storage of private keys, mnemonics, or seeds // - Logging of sensitive data // - Sending sensitive data to APIs ``` ### Secure Patterns ```typescript // CORRECT: Use sdk-dapp's secure session management import { initApp } from '@multiversx/sdk-dapp/out/methods/initApp/initApp'; initApp({ storage: { getStorageCallback: () => sessionStorage // Session only, not persistent }, dAppConfig: { nativeAuth: { expirySeconds: 3600 // Short-lived tokens } } }); ``` ### Access Token Security ```typescript // VULNERABLE: Token exposed in URL window.location.href = `https://api.example.com?accessToken=${token}`; // VULNERABLE: Token in console console.log('Auth token:', accessToken); // SECURE: Token in Authorization header, never logged fetch(apiUrl, { headers: { 'Authorization': `Bearer ${accessToken}` } }); ``` ## 4. XSS Prevention ### User-Generated Content ```typescript // VULNERABLE: Direct HTML injection const UserProfile = ({ bio }: { bio: string }) => { return
; // XSS! }; // SECURE: React's default escaping const UserProfile = ({ bio }: { bio: string }) => { return