home / skills / multiversx / mx-ai-skills / multiversx-dapp-audit

multiversx-dapp-audit skill

/skills/multiversx-dapp-audit

This skill audits frontend dApp components for wallet integration and transaction handling security, helping you harden React/TypeScript apps using sdk-dapp.

npx playbooks add skill multiversx/mx-ai-skills --skill multiversx-dapp-audit

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
9.2 KB
---
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 <div dangerouslySetInnerHTML={{ __html: bio }} />;  // XSS!
};

// SECURE: React's default escaping
const UserProfile = ({ bio }: { bio: string }) => {
    return <div>{bio}</div>;  // Automatically escaped
};

// If HTML is necessary, sanitize first
import DOMPurify from 'dompurify';

const UserProfile = ({ bio }: { bio: string }) => {
    const sanitized = DOMPurify.sanitize(bio);
    return <div dangerouslySetInnerHTML={{ __html: sanitized }} />;
};
```

### URL Handling
```typescript
// VULNERABLE: Unvalidated redirect
const handleCallback = () => {
    const returnUrl = new URLSearchParams(window.location.search).get('returnUrl');
    window.location.href = returnUrl!;  // Open redirect!
};

// SECURE: Validate redirect URL
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 = '/';  // Default safe redirect
    }
};
```

## 5. API Communication Security

### HTTPS Enforcement
```typescript
// VULNERABLE: HTTP connection
const API_URL = 'http://api.example.com';  // Insecure!

// SECURE: Always HTTPS
const API_URL = 'https://api.example.com';

// Verify in code: all API URLs must use https://
```

### Request/Response Validation
```typescript
// VULNERABLE: Trusting API response blindly
const balance = await fetch('/api/balance').then(r => r.json());
displayBalance(balance.amount);  // What if API is compromised?

// SECURE: Validate response structure
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
```bash
# Use browser DevTools Network tab to inspect:
# - All API requests and responses
# - Transaction data being sent
# - Headers (especially Authorization)
# - WebSocket messages

# Or use proxy tools:
# - Burp Suite
# - mitmproxy
# - Charles Proxy
```

### Code Review Patterns
```bash
# Search for dangerous patterns
grep -r "localStorage" src/
grep -r "dangerouslySetInnerHTML" src/
grep -r "eval(" src/
grep -r "privateKey\|mnemonic\|seed" src/
grep -r "console.log" src/  # Check for sensitive data logging
```

### 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
```typescript
// Verify wallet connection flow:
// 1. User initiates connection
// 2. Wallet provider prompts for approval
// 3. Only public address shared with dApp
// 4. No private data transmitted

// Check UnlockPanelManager usage
const unlockPanelManager = UnlockPanelManager.init({
    loginHandler: () => {
        // Verify: no sensitive data handling here
        navigate('/dashboard');
    }
});
```

### Session Management
```typescript
// Verify session security:
// - Token expiration enforced
// - Logout clears all session data
// - No persistent sensitive storage

const handleLogout = async () => {
    const provider = getAccountProvider();
    await provider.logout();
    // Verify: session storage cleared
    sessionStorage.clear();
    navigate('/');
};
```

## 8. Audit Checklist

### Transaction Security
- [ ] All transaction data validated before signing
- [ ] User shown clear transaction preview
- [ ] Recipient addresses validated
- [ ] Amount confirmations for large transfers
- [ ] Gas limits appropriate for operation

### Data Security
- [ ] No private keys in any storage
- [ ] No sensitive data in console logs
- [ ] Access tokens not exposed in URLs
- [ ] HTTPS enforced for all API calls

### XSS Prevention
- [ ] No `dangerouslySetInnerHTML` with user input
- [ ] No `eval()` with user input
- [ ] URL redirects validated
- [ ] Content-Security-Policy headers present

### Session Security
- [ ] Token expiration enforced
- [ ] Logout clears all session data
- [ ] Protected routes properly guarded
- [ ] Re-authentication for sensitive operations

## 9. Report Template

```markdown
# 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]
```

Overview

This skill audits frontend MultiversX dApp components built with @multiversx/sdk-dapp, focusing on wallet integration, transaction construction, and client-side security. It helps reviewers find vulnerabilities that could lead to funds loss, blind signing, XSS, and sensitive data exposure. The goal is actionable findings and remediation steps that improve user safety and transaction integrity.

How this skill works

The auditor inspects React/TypeScript frontend code for dangerous patterns: unsafe transaction payload construction, blind signing flows, insecure storage of keys/tokens, and unsanitized user content. It validates API usage (HTTPS, response validation), session handling, and wallet connection flows, and recommends changes like whitelisting contract calls, explicit transaction previews, and secure token handling. It also provides checks and tools to reproduce and verify issues during review.

When to use it

  • Code review of React/TypeScript MultiversX dApps using @multiversx/sdk-dapp
  • Before release or after major frontend changes that touch wallet or transaction code
  • When assessing user-facing signing or approval UX for blind signing risks
  • If you suspect sensitive data leakage in storage, logs, or URLs
  • When validating frontend-backend boundaries and API trust assumptions

Best practices

  • Whitelist allowed contract functions and validate all transaction arguments before building payloads
  • Always present a clear transaction preview (recipient, amount, token, function, gas) to users before signing
  • Never store private keys, mnemonics, or seeds in localStorage; use short-lived session storage managed by sdk-dapp
  • Sanitize any HTML or user-generated content; prefer React escaping or DOMPurify if HTML is required
  • Enforce HTTPS for all endpoints and validate API responses before using data
  • Clear session data on logout and enforce token expiry for sensitive operations

Example use cases

  • Audit a dApp that builds contract calls from user input to ensure no arbitrary payload injection
  • Review wallet connection flow to confirm no private data is transmitted and provider prompts are correct
  • Scan codebase for insecure storage or logging of tokens, keys, or mnemonics
  • Validate redirect handling and user content rendering to prevent XSS and open redirects
  • Test transaction signing UI to ensure users see meaningful previews and gas estimates

FAQ

How do I detect blind signing risks?

Search for signing calls that pass hashes or opaque data and check whether the UI shows a human-readable preview. Flag signMessage or signTransaction usage where the user only sees a hash or no context.

What are the most critical code patterns to grep for?

Look for localStorage/sessionStorage of credentials, dangerouslySetInnerHTML, eval(), console.log of tokens, and direct construction of transaction data from unvalidated inputs.