Skip to content

Latest commit

Β 

History

History
965 lines (709 loc) Β· 23.4 KB

File metadata and controls

965 lines (709 loc) Β· 23.4 KB

Donation Flow Security Audit Report

Date: February 22, 2026

Auditor: AI Security Review

Scope: End-to-end donation flow security analysis


Executive Summary

This document presents a comprehensive security audit of the donation flow in the Stellar Micro-Donation API. The audit identified 12 critical vulnerabilities, 8 high-priority issues, and 15 medium-priority concerns that require immediate attention.

Risk Level Summary

  • πŸ”΄ Critical: 12 issues (Immediate action required)
  • 🟠 High: 8 issues (Action required within 1 week)
  • 🟑 Medium: 15 issues (Action required within 1 month)
  • 🟒 Low: 7 issues (Monitor and improve)

1. CRITICAL VULNERABILITIES

1.1 Missing Permission Checks on /donations/send Endpoint

Severity: πŸ”΄ CRITICAL
Location: src/routes/donation.js:48

Issue: The /donations/send endpoint has NO authentication or authorization checks. Anyone can send donations from any wallet if they know the user ID.

router.post('/send', async (req, res) => {  // ❌ NO AUTH CHECK
  const { senderId, receiverId, amount, memo } = req.body;

Attack Vector:

  • Attacker can drain any wallet by knowing the user ID
  • No rate limiting on this endpoint
  • No permission validation

Impact: Complete loss of funds, unauthorized transactions

Recommendation:

router.post('/send', 
  checkPermission(PERMISSIONS.DONATIONS_CREATE),
  checkOwnership('senderId'), // Verify user owns the sender wallet
  async (req, res) => {

1.2 Custodial Secret Key Storage Vulnerability

Severity: πŸ”΄ CRITICAL
Location: src/routes/donation.js:93

Issue: The system stores encrypted secret keys and decrypts them server-side for transactions. This is a custodial model with severe security implications.

const secret = encryption.decrypt(sender.encryptedSecret);

Attack Vectors:

  • If encryption key is compromised, all wallets are compromised
  • Server has access to all private keys
  • Single point of failure
  • Insider threat risk

Impact: Complete loss of all user funds if server is compromised

Recommendation:

  1. Immediate: Implement non-custodial model where users sign transactions client-side
  2. Short-term: Use HSM (Hardware Security Module) for key storage
  3. Long-term: Implement multi-signature wallets
  4. Add key rotation mechanism
  5. Implement audit logging for all key access

1.3 SQL Injection Vulnerability

Severity: πŸ”΄ CRITICAL
Location: src/routes/donation.js:82-83

Issue: While parameterized queries are used, there's no input sanitization before database operations.

const sender = await Database.get('SELECT * FROM users WHERE id = ?', [senderId]);

Attack Vector:

  • If senderId contains malicious input and Database.get doesn't properly escape
  • Potential for second-order SQL injection

Recommendation:

  1. Add input validation middleware
  2. Use ORM with built-in protection
  3. Implement input sanitization layer
  4. Add database query logging

1.4 Missing Idempotency Check Implementation

Severity: πŸ”΄ CRITICAL
Location: src/routes/donation.js:149

Issue: Idempotency key is required but NOT checked for duplicates. This allows duplicate transactions.

if (!idempotencyKey) {
  return res.status(400).json({ /* error */ });
}
// ❌ NO CHECK IF KEY WAS ALREADY USED

Attack Vector:

  • Replay attacks with same idempotency key
  • Double-spending
  • Accidental duplicate donations

Impact: Financial loss, duplicate charges

Recommendation:

// Check if idempotency key was already used
const existing = await Transaction.getByIdempotencyKey(idempotencyKey);
if (existing) {
  return res.status(200).json({
    success: true,
    data: existing,
    message: 'Transaction already processed'
  });
}

1.5 No Rate Limiting on Donation Endpoints

Severity: πŸ”΄ CRITICAL
Location: All donation endpoints

Issue: No rate limiting implemented on any donation endpoint.

Attack Vectors:

  • DDoS attacks
  • Brute force attacks
  • Resource exhaustion
  • Spam donations

Recommendation:

const rateLimit = require('express-rate-limit');

const donationLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100, // limit each IP to 100 requests per windowMs
  message: 'Too many donation requests, please try again later'
});

router.post('/donations', donationLimiter, checkPermission(...), ...);

1.6 Insufficient Balance Check Before Transaction

Severity: πŸ”΄ CRITICAL
Location: src/routes/donation.js:93-105

Issue: No balance check before attempting Stellar transaction.

// ❌ NO BALANCE CHECK
const stellarResult = await stellarService.sendDonation({
  sourceSecret: secret,
  destinationPublic: receiver.publicKey,
  amount: amount,
  memo: memo
});

Attack Vector:

  • Failed transactions still recorded
  • Wasted network fees
  • Poor user experience

Recommendation:

// Check balance before transaction
const balance = await stellarService.getBalance(sender.publicKey);
if (parseFloat(balance.balance) < parseFloat(amount) + 0.00001) { // Include fee
  return res.status(400).json({
    success: false,
    error: 'Insufficient balance'
  });
}

1.7 Missing Transaction Atomicity

Severity: πŸ”΄ CRITICAL
Location: src/routes/donation.js:107-122

Issue: Database and Stellar transactions are not atomic. If one fails, the other may succeed.

// Stellar transaction
const stellarResult = await stellarService.sendDonation(...);

// Database record (separate operation)
const dbResult = await Database.run(...);

Attack Vector:

  • Money sent but not recorded in database
  • Database record created but Stellar transaction fails
  • Inconsistent state

Recommendation:

// Use transaction pattern
try {
  await Database.beginTransaction();
  
  // 1. Create pending record
  const pendingRecord = await Database.run(
    'INSERT INTO transactions (...) VALUES (...)',
    [..., 'pending']
  );
  
  // 2. Execute Stellar transaction
  const stellarResult = await stellarService.sendDonation(...);
  
  // 3. Update record to confirmed
  await Database.run(
    'UPDATE transactions SET status = ?, stellarTxId = ? WHERE id = ?',
    ['confirmed', stellarResult.transactionId, pendingRecord.id]
  );
  
  await Database.commit();
} catch (error) {
  await Database.rollback();
  throw error;
}

1.8 Weak Encryption Key Management

Severity: πŸ”΄ CRITICAL
Location: src/utils/encryption.js:11-21

Issue: Encryption key fallback to hardcoded value in development.

if (!key) {
  if (process.env.NODE_ENV === 'production') {
    throw new Error('ENCRYPTION_KEY must be set in production');
  }
  // ❌ DANGEROUS FALLBACK
  return Buffer.alloc(32, 'dev-secret-key-do-not-use-in-prod');
}

Attack Vector:

  • If NODE_ENV is not set correctly, weak key is used
  • Key derivation from string is weak
  • No key rotation mechanism

Recommendation:

  1. Always require ENCRYPTION_KEY, no fallback
  2. Use proper key derivation (PBKDF2, Argon2)
  3. Implement key rotation
  4. Store keys in secure vault (AWS KMS, HashiCorp Vault)

1.9 Missing Input Validation on Amount

Severity: πŸ”΄ CRITICAL
Location: src/routes/donation.js:68-73

Issue: Amount validation is insufficient and can be bypassed.

if (isNaN(parseFloat(amount)) || parseFloat(amount) <= 0) {
  return res.status(400).json({ error: 'Amount must be a positive number' });
}

Attack Vectors:

  • Scientific notation bypass: 1e100
  • Negative zero: -0
  • Infinity: Infinity
  • Very large numbers causing overflow
  • Very small numbers causing precision issues

Recommendation:

// Comprehensive amount validation
const amountNum = parseFloat(amount);

if (!Number.isFinite(amountNum) || amountNum <= 0) {
  return res.status(400).json({ error: 'Invalid amount' });
}

if (amountNum > Number.MAX_SAFE_INTEGER) {
  return res.status(400).json({ error: 'Amount too large' });
}

if (amountNum < 0.0000001) { // Stellar minimum
  return res.status(400).json({ error: 'Amount too small' });
}

// Check decimal places (Stellar max 7)
const decimals = amount.toString().split('.')[1];
if (decimals && decimals.length > 7) {
  return res.status(400).json({ error: 'Too many decimal places' });
}

1.10 No Transaction Timeout Handling

Severity: πŸ”΄ CRITICAL
Location: src/routes/donation.js:95-105

Issue: No timeout for Stellar transactions, can hang indefinitely.

Attack Vector:

  • Resource exhaustion
  • Hanging requests
  • Poor user experience

Recommendation:

const TRANSACTION_TIMEOUT = 30000; // 30 seconds

const stellarResult = await Promise.race([
  stellarService.sendDonation({...}),
  new Promise((_, reject) => 
    setTimeout(() => reject(new Error('Transaction timeout')), TRANSACTION_TIMEOUT)
  )
]);

1.11 Memo Injection Vulnerability

Severity: πŸ”΄ CRITICAL
Location: src/routes/donation.js:175-188

Issue: Memo validation exists but sanitization may not prevent all injection attacks.

const sanitizedMemo = memo ? memoValidator.sanitize(memo) : '';

Attack Vectors:

  • XSS if memo is displayed in web interface
  • SQL injection if memo is used in queries
  • Command injection if memo is logged to shell

Recommendation:

// Enhanced memo sanitization
const sanitizeMemo = (memo) => {
  if (!memo) return '';
  
  // Remove all control characters
  let sanitized = memo.replace(/[\x00-\x1F\x7F-\x9F]/g, '');
  
  // HTML encode special characters
  sanitized = sanitized
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&#x27;');
  
  // Truncate to Stellar limit
  return memoValidator.truncate(sanitized);
};

1.12 Missing CSRF Protection

Severity: πŸ”΄ CRITICAL
Location: All POST endpoints

Issue: No CSRF token validation on state-changing operations.

Attack Vector:

  • Cross-site request forgery
  • Unauthorized donations from victim's account

Recommendation:

const csrf = require('csurf');
const csrfProtection = csrf({ cookie: true });

app.use(csrfProtection);

// Include CSRF token in responses
router.get('/donations/csrf-token', (req, res) => {
  res.json({ csrfToken: req.csrfToken() });
});

2. HIGH PRIORITY ISSUES

2.1 Weak API Key Authentication

Severity: 🟠 HIGH
Location: src/middleware/apiKeyMiddleware.js

Issue: API keys stored in plain text in environment variables.

Recommendation:

  • Use JWT tokens with expiration
  • Implement OAuth 2.0
  • Add API key rotation
  • Hash API keys in storage

2.2 No Request Size Limits

Severity: 🟠 HIGH

Issue: No limits on request body size.

Recommendation:

app.use(express.json({ limit: '10kb' }));

2.3 Insufficient Error Information Leakage

Severity: 🟠 HIGH
Location: src/routes/donation.js:127

Issue: Error messages expose internal details.

res.status(500).json({
  success: false,
  error: 'Failed to send donation',
  message: error.message  // ❌ Exposes internal errors
});

Recommendation:

// Production error handling
if (process.env.NODE_ENV === 'production') {
  res.status(500).json({
    success: false,
    error: 'Transaction failed',
    code: 'TRANSACTION_ERROR'
  });
} else {
  // Detailed errors only in development
  res.status(500).json({
    success: false,
    error: 'Failed to send donation',
    message: error.message,
    stack: error.stack
  });
}

2.4 Missing Transaction Status Validation

Severity: 🟠 HIGH
Location: src/routes/donation.js:348

Issue: Status update endpoint doesn't verify transaction ownership.

Recommendation:

  • Add ownership check
  • Require admin permission for status updates
  • Log all status changes

2.5 No Concurrent Transaction Protection

Severity: 🟠 HIGH

Issue: Multiple simultaneous donations from same wallet can cause race conditions.

Recommendation:

  • Implement distributed locks (Redis)
  • Use database row-level locking
  • Queue transactions per wallet

2.6 Missing Audit Logging

Severity: 🟠 HIGH

Issue: No audit trail for sensitive operations.

Recommendation:

const auditLog = {
  timestamp: new Date().toISOString(),
  action: 'DONATION_CREATED',
  userId: req.user.id,
  walletId: senderId,
  amount: amount,
  ipAddress: req.ip,
  userAgent: req.headers['user-agent']
};

await AuditLog.create(auditLog);

2.7 Weak Daily Limit Enforcement

Severity: 🟠 HIGH
Location: src/routes/donation.js:213-228

Issue: Daily limit can be bypassed by using different donor names.

Recommendation:

  • Track by wallet address, not donor name
  • Implement IP-based rate limiting
  • Add device fingerprinting

2.8 No Transaction Confirmation Requirement

Severity: 🟠 HIGH

Issue: Large transactions execute immediately without confirmation.

Recommendation:

if (amount > 1000) { // Large transaction threshold
  // Require 2FA or email confirmation
  const confirmationToken = generateToken();
  await sendConfirmationEmail(user.email, confirmationToken);
  
  return res.status(202).json({
    success: true,
    message: 'Confirmation required',
    confirmationToken
  });
}

3. MEDIUM PRIORITY ISSUES

3.1 Missing Input Sanitization

Severity: 🟑 MEDIUM

Issue: Donor and recipient fields not sanitized.

Recommendation:

  • Validate Stellar address format
  • Sanitize all string inputs
  • Implement whitelist validation

3.2 No Transaction Expiry

Severity: 🟑 MEDIUM

Issue: Pending transactions never expire.

Recommendation:

  • Add expiry timestamp to transactions
  • Implement cleanup job for expired transactions

3.3 Insufficient Memo Validation

Severity: 🟑 MEDIUM
Location: src/utils/memoValidator.js

Issue: Only checks byte length and control characters.

Recommendation:

  • Add profanity filter
  • Check for malicious patterns
  • Implement content moderation

3.4 Missing Transaction Limits Per Time Window

Severity: 🟑 MEDIUM

Issue: Only daily limit exists, no hourly/minute limits.

Recommendation:

  • Add sliding window rate limiting
  • Implement per-minute transaction limits
  • Add burst protection

3.5 No Webhook Signature Verification

Severity: 🟑 MEDIUM

Issue: If webhooks are added later, no signature verification planned.

Recommendation:

  • Implement HMAC signature verification
  • Add replay attack protection
  • Use timestamp validation

3.6 Weak Fee Calculation Validation

Severity: 🟑 MEDIUM
Location: src/utils/feeCalculator.js

Issue: Fee calculation can be manipulated.

Recommendation:

  • Server-side fee calculation only
  • Don't accept fee from client
  • Validate fee percentage bounds

3.7 Missing Transaction Metadata

Severity: 🟑 MEDIUM

Issue: Transactions don't store IP, user agent, or geolocation.

Recommendation:

  • Add metadata fields to transaction table
  • Store for fraud detection
  • Implement anomaly detection

3.8 No Stellar Network Status Check

Severity: 🟑 MEDIUM

Issue: Doesn't check if Stellar network is operational before transactions.

Recommendation:

const networkStatus = await stellarService.checkNetworkHealth();
if (!networkStatus.operational) {
  return res.status(503).json({
    error: 'Stellar network temporarily unavailable'
  });
}

3.9 Missing Transaction Priority Queue

Severity: 🟑 MEDIUM

Issue: All transactions treated equally, no priority system.

Recommendation:

  • Implement priority queue for large donations
  • Add VIP user fast-track
  • Queue management for high load

3.10 No Duplicate Detection Beyond Idempotency

Severity: 🟑 MEDIUM

Issue: Same amount to same recipient at same time not detected.

Recommendation:

  • Implement fuzzy duplicate detection
  • Add confirmation for suspicious patterns
  • Machine learning for fraud detection

3.11 Insufficient Validation Error Messages

Severity: 🟑 MEDIUM

Issue: Error messages don't always indicate what's wrong.

Recommendation:

  • Provide specific field-level errors
  • Include validation rules in error response
  • Add error codes for client handling

3.12 No Transaction Cancellation

Severity: 🟑 MEDIUM

Issue: No way to cancel pending transactions.

Recommendation:

  • Add cancellation endpoint
  • Implement refund mechanism
  • Add dispute resolution process

3.13 Missing Stellar Transaction Fee Handling

Severity: 🟑 MEDIUM

Issue: Stellar network fees not accounted for in balance checks.

Recommendation:

const STELLAR_BASE_FEE = 0.00001; // 100 stroops
const totalRequired = parseFloat(amount) + STELLAR_BASE_FEE;

if (balance < totalRequired) {
  return res.status(400).json({
    error: 'Insufficient balance including network fee',
    required: totalRequired,
    available: balance
  });
}

3.14 No Transaction Batching

Severity: 🟑 MEDIUM

Issue: Each donation is individual transaction, inefficient for multiple donations.

Recommendation:

  • Implement transaction batching
  • Add bulk donation endpoint
  • Optimize for gas fees

3.15 Missing Stellar Memo Type Support

Severity: 🟑 MEDIUM
Location: src/utils/memoValidator.js

Issue: Only supports MEMO_TEXT, not MEMO_ID, MEMO_HASH, or MEMO_RETURN.

Recommendation:

  • Support all Stellar memo types
  • Add memo type parameter
  • Validate based on memo type

4. LOW PRIORITY ISSUES

4.1 No Transaction Analytics

Severity: 🟒 LOW

Recommendation: Add analytics for fraud detection and business intelligence.


4.2 Missing Transaction Tags

Severity: 🟒 LOW

Recommendation: Allow users to tag transactions for organization.


4.3 No Multi-Currency Support

Severity: 🟒 LOW

Recommendation: Plan for future multi-asset support.


4.4 Missing Transaction Notes

Severity: 🟒 LOW

Recommendation: Allow private notes separate from blockchain memo.


4.5 No Transaction Search

Severity: 🟒 LOW

Recommendation: Implement full-text search on transactions.


4.6 Missing Export Functionality

Severity: 🟒 LOW

Recommendation: Add CSV/PDF export for tax purposes.


4.7 No Transaction Scheduling

Severity: 🟒 LOW

Recommendation: Allow scheduling donations for future dates.


5. ABUSE VECTORS IDENTIFIED

5.1 Wallet Draining Attack

Vector: Attacker discovers user IDs and drains wallets via /donations/send
Mitigation: Add authentication and ownership verification

5.2 Replay Attack

Vector: Reuse idempotency keys to duplicate transactions
Mitigation: Implement idempotency key tracking

5.3 Race Condition Exploit

Vector: Send multiple simultaneous donations to overdraw wallet
Mitigation: Implement locking mechanism

5.4 Memo Injection

Vector: Inject malicious content via memo field
Mitigation: Enhanced sanitization and validation

5.5 Amount Manipulation

Vector: Use scientific notation or edge cases to bypass limits
Mitigation: Comprehensive amount validation

5.6 DDoS Attack

Vector: Flood donation endpoints to exhaust resources
Mitigation: Rate limiting and request throttling

5.7 Timing Attack

Vector: Measure response times to infer wallet balances
Mitigation: Constant-time operations, add random delays

5.8 Enumeration Attack

Vector: Enumerate valid user IDs and wallet addresses
Mitigation: Generic error messages, rate limiting


6. RECOMMENDED SECURITY CONTROLS

6.1 Immediate Actions (Week 1)

  1. βœ… Add authentication to /donations/send
  2. βœ… Implement idempotency key checking
  3. βœ… Add rate limiting to all endpoints
  4. βœ… Implement balance checks before transactions
  5. βœ… Add comprehensive amount validation
  6. βœ… Implement transaction atomicity

6.2 Short-term Actions (Month 1)

  1. βœ… Migrate to non-custodial model
  2. βœ… Implement proper key management (HSM/KMS)
  3. βœ… Add audit logging
  4. βœ… Implement CSRF protection
  5. βœ… Add request size limits
  6. βœ… Improve error handling

6.3 Long-term Actions (Quarter 1)

  1. βœ… Implement multi-signature wallets
  2. βœ… Add fraud detection system
  3. βœ… Implement transaction monitoring
  4. βœ… Add compliance checks (AML/KYC)
  5. βœ… Implement disaster recovery
  6. βœ… Add security testing automation

7. COMPLIANCE CONSIDERATIONS

7.1 Financial Regulations

  • AML (Anti-Money Laundering): Implement transaction monitoring
  • KYC (Know Your Customer): Add identity verification for large transactions
  • CTF (Counter-Terrorism Financing): Screen against sanctions lists

7.2 Data Protection

  • GDPR: Add data retention policies, right to deletion
  • PCI DSS: If handling card data, ensure compliance
  • SOC 2: Implement security controls for audit

7.3 Blockchain Regulations

  • Travel Rule: For transactions > $1000, collect sender/receiver info
  • Licensing: Check if money transmitter license required
  • Tax Reporting: Implement 1099 reporting for US users

8. TESTING RECOMMENDATIONS

8.1 Security Testing

  • Penetration testing by third party
  • Automated security scanning (SAST/DAST)
  • Dependency vulnerability scanning
  • Fuzz testing on all inputs

8.2 Load Testing

  • Stress test donation endpoints
  • Test concurrent transaction handling
  • Verify rate limiting effectiveness

8.3 Integration Testing

  • Test Stellar network failure scenarios
  • Test database transaction rollbacks
  • Test idempotency key handling

9. MONITORING AND ALERTING

9.1 Critical Alerts

  • Failed transactions > 5% in 5 minutes
  • Unusual transaction patterns
  • Multiple failed authentication attempts
  • Encryption key access
  • Large transactions (> $10,000)

9.2 Metrics to Track

  • Transaction success rate
  • Average transaction time
  • API error rates
  • Rate limit hits
  • Wallet balance changes

10. INCIDENT RESPONSE PLAN

10.1 Security Incident Procedures

  1. Detect and alert
  2. Isolate affected systems
  3. Investigate and contain
  4. Eradicate threat
  5. Recover systems
  6. Post-incident review

10.2 Breach Notification

  • Notify users within 72 hours
  • Report to regulators as required
  • Document incident thoroughly
  • Implement preventive measures

CONCLUSION

The donation flow has significant security vulnerabilities that require immediate attention. The most critical issues are:

  1. Missing authentication on /donations/send - Allows unauthorized wallet access
  2. Custodial key storage - Single point of failure for all funds
  3. No idempotency checking - Allows duplicate transactions
  4. Missing rate limiting - Vulnerable to abuse
  5. Insufficient input validation - Multiple injection vectors

Recommended Priority:

  1. Week 1: Fix all CRITICAL issues (1.1-1.12)
  2. Month 1: Address HIGH priority issues (2.1-2.8)
  3. Quarter 1: Resolve MEDIUM priority issues (3.1-3.15)
  4. Ongoing: Monitor and improve LOW priority items

Estimated Effort: 4-6 weeks for critical fixes, 3-4 months for complete remediation.


Report Status: DRAFT
Next Review: After critical fixes implemented
Approval Required: Security Team, Engineering Lead, Product Owner