| name | mvx-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
const sendTransaction = async (userInput: string) => {
const tx = new Transaction({
receiver: Address.newFromBech32(recipientAddress),
data: Buffer.from(userInput),
});
await signAndSend(tx);
};
const sendTransaction = async (functionName: string, args: string[]) => {
const allowedFunctions = ['stake', 'unstake', 'claim'];
if (!allowedFunctions.includes(functionName)) {
throw new Error('Invalid function');
}
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:
const signMessage = async (data: string) => {
const hash = keccak256(data);
return await wallet.signMessage(hash);
};
const signMessage = async (message: string) => {
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
localStorage.setItem('privateKey', wallet.privateKey);
localStorage.setItem('mnemonic', wallet.mnemonic);
sessionStorage.setItem('seed', wallet.seed);
Secure Patterns
import { initApp } from '@multiversx/sdk-dapp/out/methods/initApp/initApp';
initApp({
storage: {
getStorageCallback: () => sessionStorage
},
dAppConfig: {
nativeAuth: {
expirySeconds: 3600
}
}
});
Access Token Security
window.location.href = `https://api.example.com?accessToken=${token}`;
console.log('Auth token:', accessToken);
fetch(apiUrl, {
headers: {
'Authorization': `Bearer ${accessToken}`
}
});
4. XSS Prevention
User-Generated Content
const UserProfile = ({ bio }: { bio: string }) => {
return <div dangerouslySetInnerHTML={{ __html: bio }} />;
};
const UserProfile = ({ bio }: { bio: string }) => {
return <div>{bio}</div>;
};
import DOMPurify from 'dompurify';
const UserProfile = ({ bio }: { bio: string }) => {
const sanitized = DOMPurify.sanitize(bio);
return <div dangerouslySetInnerHTML={{ __html: sanitized }} />;
};
URL Handling
const handleCallback = () => {
const returnUrl = new URLSearchParams(window.location.search).get('returnUrl');
window.location.href = returnUrl!;
};
const handleCallback = () => {
const returnUrl = new URLSearchParams(window.location.search).get('returnUrl');
const allowed = ['/', '/dashboard', '/profile'];
if (allowed.includes(returnUrl || '')) {
window.location.href = returnUrl!;
} else {
window.location.href = '/';
}
};
5. API Communication Security
HTTPS Enforcement
const API_URL = 'http://api.example.com';
const API_URL = 'https://api.example.com';
Request/Response Validation
const balance = await fetch('/api/balance').then(r => r.json());
displayBalance(balance.amount);
const response = await fetch('/api/balance').then(r => r.json());
if (typeof response.amount !== 'string' || !/^\d+$/.test(response.amount)) {
throw new Error('Invalid balance response');
}
displayBalance(response.amount);
6. Audit Tools and Techniques
Network Traffic Analysis
Code Review Patterns
grep -r "localStorage" src/
grep -r "dangerouslySetInnerHTML" src/
grep -r "eval(" src/
grep -r "privateKey\|mnemonic\|seed" src/
grep -r "console.log" src/
Browser Security Headers Check
Content-Security-Policy: default-src 'self'; script-src 'self'
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
7. Authentication Flow Audit
Wallet Connection
const unlockPanelManager = UnlockPanelManager.init({
loginHandler: () => {
navigate('/dashboard');
}
});
Session Management
const handleLogout = async () => {
const provider = getAccountProvider();
await provider.logout();
sessionStorage.clear();
navigate('/');
};
8. Audit Checklist
Transaction Security
Data Security
XSS Prevention
Session Security
9. Report Template
# dApp Security Audit Report
## Scope
- Application: [name]
- Version: [version]
- Files reviewed: [count]
## Findings
### Critical
| ID | Description | Location | Recommendation |
|----|-------------|----------|----------------|
| C1 | ... | ... | ... |
### High
...
### Medium
...
### Informational
...
## Recommendations Summary
1. [Priority recommendation]
2. ...
## Conclusion
[Overall assessment]