Files
impersonator/docs/security/SECURITY_TESTING_GUIDE.md

584 lines
14 KiB
Markdown
Raw Permalink Normal View History

feat: comprehensive project improvements and fixes - Fix all TypeScript compilation errors (40+ fixes) - Add missing type definitions (TransactionRequest, SafeInfo) - Fix TransactionRequestStatus vs TransactionStatus confusion - Fix import paths and provider type issues - Fix test file errors and mock providers - Implement comprehensive security features - AES-GCM encryption with PBKDF2 key derivation - Input validation and sanitization - Rate limiting and nonce management - Replay attack prevention - Access control and authorization - Add comprehensive test suite - Integration tests for transaction flow - Security validation tests - Wallet management tests - Encryption and rate limiter tests - E2E tests with Playwright - Add extensive documentation - 12 numbered guides (setup, development, API, security, etc.) - Security documentation and audit reports - Code review and testing reports - Project organization documentation - Update dependencies - Update axios to latest version (security fix) - Update React types to v18 - Fix peer dependency warnings - Add development tooling - CI/CD workflows (GitHub Actions) - Pre-commit hooks (Husky) - Linting and formatting (Prettier, ESLint) - Security audit workflow - Performance benchmarking - Reorganize project structure - Move reports to docs/reports/ - Clean up root directory - Organize documentation - Add new features - Smart wallet management (Gnosis Safe, ERC4337) - Transaction execution and approval workflows - Balance management and token support - Error boundary and monitoring (Sentry) - Fix WalletConnect configuration - Handle missing projectId gracefully - Add environment variable template
2026-01-14 02:17:26 -08:00
# Security Testing Guide
This guide provides comprehensive testing procedures for all security aspects of the Impersonator Smart Wallet system.
## Pre-Testing Setup
1. Install testing dependencies:
```bash
npm install --save-dev @testing-library/react @testing-library/jest-dom jest jest-environment-jsdom
```
2. Set up test environment variables
3. Configure test database/storage mocks
---
## Test Categories
### 1. Input Validation Tests
#### Address Validation
```typescript
describe("Address Validation", () => {
test("rejects malicious addresses", () => {
const malicious = [
"<script>alert('xss')</script>",
"javascript:alert('xss')",
"../../etc/passwd",
"0x" + "a".repeat(1000), // Too long
"0xGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG", // Invalid hex
];
malicious.forEach(addr => {
expect(validateAddress(addr).valid).toBe(false);
});
});
test("detects contract addresses", async () => {
const contractAddr = "0x..."; // Known contract
const isContract = await isContractAddress(contractAddr, provider);
expect(isContract).toBe(true);
});
});
```
#### Transaction Data Validation
```typescript
describe("Transaction Data Validation", () => {
test("rejects malicious bytecode", () => {
const malicious = [
"0x" + "00".repeat(50000), // Too large
"0xdeadbeef<script>", // Invalid hex
"javascript:alert(1)", // XSS attempt
];
malicious.forEach(data => {
expect(validateTransactionData(data).valid).toBe(false);
});
});
});
```
---
### 2. Access Control Tests
#### Owner Management
```typescript
describe("Owner Management Security", () => {
test("prevents unauthorized owner addition", async () => {
const wallet = createTestWallet();
const unauthorized = "0xUnauthorizedAddress";
await expect(
addOwner(wallet.id, { address: unauthorized }, unauthorized)
).rejects.toThrow("Unauthorized");
});
test("prevents removing last owner", async () => {
const wallet = createTestWallet({ owners: ["0xOwner1"] });
await expect(
removeOwner(wallet.id, "0xOwner1")
).rejects.toThrow("Cannot remove last owner");
});
test("prevents threshold > owners", async () => {
const wallet = createTestWallet({ owners: ["0x1", "0x2"], threshold: 1 });
await expect(
updateThreshold(wallet.id, 5)
).rejects.toThrow("Threshold cannot exceed owner count");
});
});
```
---
### 3. Race Condition Tests
#### Concurrent Approvals
```typescript
describe("Race Condition Tests", () => {
test("handles concurrent approvals correctly", async () => {
const tx = createTestTransaction();
const approvers = ["0xApprover1", "0xApprover2", "0xApprover3"];
// Approve simultaneously
const promises = approvers.map(addr =>
approveTransaction(tx.id, addr)
);
await Promise.all(promises);
// Verify all approvals recorded
const pending = getPendingTransaction(tx.id);
expect(pending.approvalCount).toBe(3);
expect(pending.approvals.length).toBe(3);
});
test("prevents duplicate approvals", async () => {
const tx = createTestTransaction();
const approver = "0xApprover1";
await approveTransaction(tx.id, approver);
// Try to approve again
await expect(
approveTransaction(tx.id, approver)
).rejects.toThrow("Already approved");
});
});
```
---
### 4. Message Security Tests
#### postMessage Security
```typescript
describe("postMessage Security", () => {
test("only sends to allowed origins", () => {
const allowedOrigin = "https://app.example.com";
const maliciousOrigin = "https://evil.com";
const message = { method: "getSafeInfo", data: {} };
// Should only send to allowed origin
sendMessageToIFrame(message, allowedOrigin);
// Should not send to malicious origin
expect(() => {
sendMessageToIFrame(message, maliciousOrigin);
}).toThrow();
});
test("validates message structure", () => {
const invalidMessages = [
{ method: "unknownMethod" },
{ data: "not an object" },
null,
undefined,
];
invalidMessages.forEach(msg => {
expect(isValidMessage(msg as any)).toBe(false);
});
});
test("prevents message replay", () => {
const message = createTestMessage();
// First message should be valid
expect(isValidMessage(message)).toBe(true);
// Immediate replay should be rejected
expect(isValidMessage(message)).toBe(false);
});
});
```
---
### 5. Storage Security Tests
#### Encryption Tests
```typescript
describe("Storage Encryption", () => {
test("encrypts sensitive data", async () => {
const sensitive = JSON.stringify({
owners: ["0xOwner1", "0xOwner2"],
threshold: 2,
});
await secureStorage.setItem("test", sensitive);
const stored = localStorage.getItem("test");
expect(stored).not.toBe(sensitive);
expect(stored).toContain("encrypted"); // Check encryption marker
});
test("decrypts data correctly", async () => {
const original = "sensitive data";
await secureStorage.setItem("test", original);
const decrypted = await secureStorage.getItem("test");
expect(decrypted).toBe(original);
});
test("handles tampered data", async () => {
localStorage.setItem("test", "tampered-encrypted-data");
await expect(
secureStorage.getItem("test")
).rejects.toThrow("Decryption failed");
});
});
```
---
### 6. Transaction Security Tests
#### Transaction Validation
```typescript
describe("Transaction Security", () => {
test("prevents integer overflow", () => {
const largeValue = "115792089237316195423570985008687907853269984665640564039457584007913129639936"; // Max uint256 + 1
const result = validateTransactionValue(largeValue);
expect(result.valid).toBe(false);
});
test("prevents duplicate transactions", async () => {
const tx = {
from: "0xFrom",
to: "0xTo",
value: "1000",
data: "0x",
};
await createTransaction(tx);
// Try to create duplicate
await expect(
createTransaction(tx)
).rejects.toThrow("Duplicate transaction");
});
test("enforces gas limits", () => {
const excessiveGas = "20000000"; // 20M gas
const result = validateGasLimit(excessiveGas);
expect(result.valid).toBe(false);
});
test("validates transaction amounts", () => {
const excessiveAmount = ethers.utils.parseEther("2000000").toString(); // 2M ETH
const result = validateTransactionValue(excessiveAmount);
expect(result.valid).toBe(false);
});
});
```
---
### 7. Provider Security Tests
#### Provider Verification
```typescript
describe("Provider Security", () => {
test("rejects unverified providers", () => {
const fakeProvider = {
request: () => Promise.resolve([]),
// Missing isMetaMask, isCoinbaseWallet, etc.
};
expect(verifyProvider(fakeProvider)).toBe(false);
});
test("verifies account matches wallet", async () => {
const wallet = createTestWallet({ address: "0xWallet" });
const provider = createMockProvider({ accounts: ["0xDifferent"] });
await expect(
executeTransaction(txId, provider)
).rejects.toThrow("Account does not match");
});
});
```
---
### 8. Network Security Tests
#### RPC URL Validation
```typescript
describe("Network Security", () => {
test("rejects HTTP URLs in production", () => {
const httpUrl = "http://malicious-rpc.com";
const result = validateRpcUrl(httpUrl);
expect(result.valid).toBe(false);
});
test("validates network IDs", () => {
const invalidNetworks = [-1, 0, 99999, 1.5];
invalidNetworks.forEach(networkId => {
expect(validateNetworkId(networkId).valid).toBe(false);
});
});
});
```
---
### 9. Multi-Sig Security Tests
#### Approval Workflow
```typescript
describe("Multi-Sig Security", () => {
test("requires threshold approvals", async () => {
const wallet = createTestWallet({ threshold: 3, owners: ["0x1", "0x2", "0x3", "0x4"] });
const tx = createTestTransaction();
// Approve with 2 owners (below threshold)
await approveTransaction(tx.id, "0x1");
await approveTransaction(tx.id, "0x2");
const pending = getPendingTransaction(tx.id);
expect(pending.canExecute).toBe(false);
// Third approval should enable execution
await approveTransaction(tx.id, "0x3");
const updated = getPendingTransaction(tx.id);
expect(updated.canExecute).toBe(true);
});
test("prevents execution without threshold", async () => {
const wallet = createTestWallet({ threshold: 2 });
const tx = createTestTransaction();
// Only one approval
await approveTransaction(tx.id, "0x1");
// Try to execute
await expect(
executeTransaction(tx.id)
).rejects.toThrow("Insufficient approvals");
});
});
```
---
### 10. Integration Security Tests
#### End-to-End Security
```typescript
describe("Integration Security", () => {
test("complete attack scenario: XSS + CSRF", async () => {
// Simulate XSS attack
const maliciousScript = "<script>stealData()</script>";
const address = maliciousScript + "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb";
// Should sanitize and extract valid address
const result = validateAddress(address);
expect(result.valid).toBe(false);
});
test("prevents transaction manipulation", async () => {
const originalTx = createTestTransaction();
// Try to modify transaction
const modifiedTx = {
...originalTx,
to: "0xAttacker",
value: "1000000000000000000000", // 1000 ETH
};
// Should reject or require re-approval
await expect(
updateTransaction(originalTx.id, modifiedTx)
).rejects.toThrow("Cannot modify approved transaction");
});
});
```
---
## Penetration Testing Scenarios
### Scenario 1: XSS Attack
1. Inject `<script>alert(document.cookie)</script>` in address field
2. Verify it's sanitized/blocked
3. Check localStorage is not accessible
### Scenario 2: CSRF Attack
1. Create malicious site that sends transaction requests
2. Verify origin validation prevents execution
3. Check CSRF tokens are required
### Scenario 3: Replay Attack
1. Capture transaction request
2. Replay same transaction
3. Verify nonce prevents duplicate execution
### Scenario 4: Race Condition Attack
1. Send 100 concurrent approval requests
2. Verify all are processed correctly
3. Check threshold is not bypassed
### Scenario 5: Integer Overflow
1. Send transaction with value > max uint256
2. Verify BigNumber handles correctly
3. Check no precision loss
---
## Automated Security Scanning
### 1. Dependency Scanning
```bash
npm audit
npm audit fix
```
### 2. Code Scanning
```bash
# Use ESLint security plugin
npm install --save-dev eslint-plugin-security
# Run security linting
npm run lint:security
```
### 3. Static Analysis
```bash
# Use SonarQube or similar
sonar-scanner
```
---
## Manual Testing Checklist
### Input Validation
- [ ] All address inputs validated
- [ ] Contract addresses rejected as owners
- [ ] Transaction data sanitized
- [ ] Value inputs use BigNumber
- [ ] Network IDs validated
### Access Control
- [ ] Only owners can modify wallet
- [ ] Threshold changes verified
- [ ] Owner additions require authorization
- [ ] Transaction approvals tracked correctly
### Message Security
- [ ] postMessage uses specific origins
- [ ] Message validation prevents injection
- [ ] Replay protection works
- [ ] Timestamp validation active
### Storage Security
- [ ] Sensitive data encrypted
- [ ] Keys not stored in localStorage
- [ ] Data can be decrypted correctly
- [ ] Tampered data rejected
### Transaction Security
- [ ] Nonces managed correctly
- [ ] Duplicate transactions prevented
- [ ] Gas limits enforced
- [ ] Amount limits enforced
- [ ] Expiration checked
### Provider Security
- [ ] Providers verified
- [ ] Accounts match wallets
- [ ] No fake providers accepted
- [ ] Signer validation works
---
## Performance Under Attack
### Load Testing
```typescript
describe("Performance Under Attack", () => {
test("handles spam transactions", async () => {
// Create 1000 transactions rapidly
const promises = Array(1000).fill(0).map((_, i) =>
createTransaction({
from: "0xFrom",
to: "0xTo",
value: "0",
data: "0x",
})
);
const start = Date.now();
await Promise.all(promises);
const duration = Date.now() - start;
// Should complete in reasonable time
expect(duration).toBeLessThan(10000); // 10 seconds
});
test("rate limiting prevents DoS", async () => {
const limiter = new RateLimiter(10, 60000);
const key = "test-key";
// First 10 should succeed
for (let i = 0; i < 10; i++) {
expect(limiter.checkLimit(key)).toBe(true);
}
// 11th should fail
expect(limiter.checkLimit(key)).toBe(false);
});
});
```
---
## Reporting Security Issues
If you find security vulnerabilities:
1. **DO NOT** create public issues
2. Email security team directly
3. Include:
- Description of vulnerability
- Steps to reproduce
- Potential impact
- Suggested fix
---
## Continuous Security Monitoring
### Daily Checks
- [ ] Review error logs for suspicious activity
- [ ] Check for failed validations
- [ ] Monitor transaction patterns
### Weekly Checks
- [ ] Review dependency updates
- [ ] Check for new CVEs
- [ ] Review access logs
### Monthly Checks
- [ ] Full security audit
- [ ] Penetration testing
- [ ] Code review
---
## Security Metrics to Track
1. **Failed Validations**: Count of rejected inputs
2. **Rate Limit Hits**: Number of rate-limited requests
3. **Suspicious Transactions**: Transactions flagged for review
4. **Provider Verification Failures**: Failed provider checks
5. **Encryption Failures**: Failed encryption/decryption attempts
6. **Message Replay Attempts**: Blocked replay attacks
---
## Conclusion
Regular security testing is essential. Run these tests:
- Before every release
- After major changes
- Monthly as part of security review
- After security incidents
Keep this guide updated as new threats emerge.