Skip to main content

Overview

The ZKScore Identity SBT contract implements comprehensive security measures to protect against common attack vectors and ensure the integrity of the soulbound token system. This document outlines the security features, audit results, and best practices for secure integration.
Always follow security best practices when integrating with smart contracts. Never trust user input without validation and always implement proper error handling.

Security Features

Access Control

The contract implements role-based access control using OpenZeppelin’s AccessControl library:
// Role definitions
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
bytes32 public constant ADMIN_ROLE = keccak256("ADMIN_ROLE");
bytes32 public constant METADATA_ROLE = keccak256("METADATA_ROLE");

// Access control modifiers
modifier onlyRole(bytes32 role) {
    require(hasRole(role, msg.sender), "AccessControl: account is missing role");
    _;
}
Security Benefits:
  • Granular permission control
  • Prevents unauthorized minting
  • Protects administrative functions
  • Enables role delegation

Reentrancy Protection

All external calls are protected against reentrancy attacks:
// ReentrancyGuard from OpenZeppelin
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

contract IdentitySBT is ReentrancyGuard {
    function mint(address to, string memory name, string memory metadataURI) 
        external 
        onlyRole(MINTER_ROLE) 
        nonReentrant 
        returns (uint256) {
        // Implementation
    }
}
Security Benefits:
  • Prevents reentrancy attacks
  • Protects against recursive calls
  • Ensures state consistency
  • Maintains gas efficiency

Input Validation

All inputs are validated before processing:
function mint(address to, string memory name, string memory metadataURI) 
    external 
    onlyRole(MINTER_ROLE) 
    nonReentrant 
    returns (uint256) {
    
    // Input validation
    require(to != address(0), "Cannot mint to zero address");
    require(bytes(name).length > 0, "Name cannot be empty");
    require(bytes(name).length <= 63, "Name too long");
    require(bytes(metadataURI).length > 0, "Metadata URI cannot be empty");
    
    // Check for duplicate names
    require(!_nameExists[name], "Name already exists");
    
    // Implementation
}
Security Benefits:
  • Prevents invalid inputs
  • Protects against overflow attacks
  • Ensures data integrity
  • Improves user experience

Soulbound Token Protection

The contract implements soulbound token mechanics to prevent transfers after activation:
function _beforeTokenTransfer(
    address from,
    address to,
    uint256 tokenId
) internal override {
    // Prevent transfers of activated tokens
    require(!isActivated(tokenId), "Token is soulbound");
    super._beforeTokenTransfer(from, to, tokenId);
}

function approve(address to, uint256 tokenId) public override {
    require(!isActivated(tokenId), "Token is soulbound");
    super.approve(to, tokenId);
}
Security Benefits:
  • Prevents unauthorized transfers
  • Maintains token ownership integrity
  • Protects against social engineering
  • Ensures soulbound nature

Audit Results

Security Audit by ConsenSys Diligence

Audit Date: January 2024
Audit Firm: ConsenSys Diligence
Severity: No critical or high-severity issues found

Audit Summary

The audit covered:
  • Smart contract security analysis
  • Access control mechanisms
  • Reentrancy protection
  • Input validation
  • Gas optimization
  • Upgrade safety

Key Findings

  1. No Critical Issues: No critical vulnerabilities found
  2. No High Severity Issues: No high-severity vulnerabilities found
  3. Minor Recommendations: Several minor recommendations for improvement
  4. Best Practices: Contract follows security best practices

Recommendations Implemented

  1. Enhanced Input Validation: Added comprehensive input validation
  2. Gas Optimization: Optimized gas usage for better efficiency
  3. Event Logging: Enhanced event logging for better monitoring
  4. Error Messages: Improved error messages for better debugging

Audit Report

The complete audit report is available at: ConsenSys Diligence Audit Report

Known Limitations

Technical Limitations

  1. Metadata Immutability: Once activated, metadata cannot be changed
  2. Transfer Irreversibility: Once activated, tokens cannot be transferred
  3. Gas Costs: Complex operations may have higher gas costs
  4. Network Dependency: Contract behavior depends on network state

Security Considerations

  1. Private Key Security: Users must secure their private keys
  2. Metadata Security: Metadata URIs should be secure and accessible
  3. Role Management: Admin roles should be carefully managed
  4. Upgrade Safety: Core logic is immutable, only parameters are configurable

Security Best Practices

For Developers

Input Validation

// Always validate inputs before sending transactions
function validateMintInputs(to, name, metadataURI) {
  if (!to || to === '0x0000000000000000000000000000000000000000') {
    throw new Error('Invalid recipient address');
  }
  
  if (!name || name.length === 0) {
    throw new Error('Name cannot be empty');
  }
  
  if (name.length > 63) {
    throw new Error('Name too long');
  }
  
  if (!metadataURI || metadataURI.length === 0) {
    throw new Error('Metadata URI cannot be empty');
  }
  
  // Validate URI format
  try {
    new URL(metadataURI);
  } catch (error) {
    throw new Error('Invalid metadata URI format');
  }
}

Error Handling

// Implement comprehensive error handling
async function safeMint(to, name, metadataURI) {
  try {
    // Validate inputs
    validateMintInputs(to, name, metadataURI);
    
    // Estimate gas
    const gasEstimate = await contract.estimateGas.mint(to, name, metadataURI);
    
    // Send transaction with proper gas limit
    const tx = await contract.mint(to, name, metadataURI, {
      gasLimit: gasEstimate.mul(120).div(100) // 20% buffer
    });
    
    const receipt = await tx.wait();
    return receipt;
  } catch (error) {
    // Handle specific error types
    if (error.message.includes('AccessControl')) {
      throw new Error('Insufficient permissions to mint');
    } else if (error.message.includes('name already exists')) {
      throw new Error('Name is already taken');
    } else if (error.message.includes('gas limit exceeded')) {
      throw new Error('Transaction gas limit exceeded');
    } else {
      throw new Error(`Minting failed: ${error.message}`);
    }
  }
}

Event Monitoring

// Monitor events for security purposes
class SecurityMonitor {
  constructor(contract) {
    this.contract = contract;
    this.setupEventMonitoring();
  }
  
  setupEventMonitoring() {
    // Monitor for suspicious activity
    this.contract.on('IdentityMinted', (to, tokenId, name, event) => {
      this.logMintEvent(to, tokenId, name, event);
    });
    
    this.contract.on('IdentityActivated', (tokenId, owner, event) => {
      this.logActivationEvent(tokenId, owner, event);
    });
  }
  
  logMintEvent(to, tokenId, name, event) {
    console.log(`Security: Identity minted`, {
      to,
      tokenId: tokenId.toString(),
      name,
      blockNumber: event.blockNumber,
      transactionHash: event.transactionHash
    });
  }
  
  logActivationEvent(tokenId, owner, event) {
    console.log(`Security: Identity activated`, {
      tokenId: tokenId.toString(),
      owner,
      blockNumber: event.blockNumber,
      transactionHash: event.transactionHash
    });
  }
}

For Users

Private Key Security

  1. Use Hardware Wallets: Use hardware wallets for maximum security
  2. Secure Storage: Store private keys in secure locations
  3. Backup Keys: Create secure backups of private keys
  4. Never Share: Never share private keys with anyone

Transaction Security

  1. Verify Recipients: Always verify recipient addresses
  2. Check Gas Limits: Ensure adequate gas limits
  3. Review Transactions: Review transactions before signing
  4. Use Testnet: Test on testnet before mainnet

Security Monitoring

Event-Based Monitoring

// Monitor for security events
class SecurityEventMonitor {
  constructor(contract) {
    this.contract = contract;
    this.suspiciousActivity = [];
    this.setupMonitoring();
  }
  
  setupMonitoring() {
    // Monitor for rapid minting
    this.contract.on('IdentityMinted', (to, tokenId, name, event) => {
      this.checkRapidMinting(to, event);
    });
    
    // Monitor for activation patterns
    this.contract.on('IdentityActivated', (tokenId, owner, event) => {
      this.checkActivationPatterns(tokenId, owner, event);
    });
  }
  
  checkRapidMinting(to, event) {
    const now = Date.now();
    const recentMints = this.suspiciousActivity.filter(
      activity => activity.type === 'mint' && 
      activity.to === to && 
      (now - activity.timestamp) < 60000 // 1 minute
    );
    
    if (recentMints.length > 5) {
      console.warn(`Suspicious activity: Rapid minting detected for ${to}`);
      this.suspiciousActivity.push({
        type: 'rapid_minting',
        to,
        timestamp: now,
        blockNumber: event.blockNumber
      });
    }
  }
  
  checkActivationPatterns(tokenId, owner, event) {
    // Check for activation patterns
    const recentActivations = this.suspiciousActivity.filter(
      activity => activity.type === 'activation' && 
      activity.owner === owner &&
      (Date.now() - activity.timestamp) < 300000 // 5 minutes
    );
    
    if (recentActivations.length > 10) {
      console.warn(`Suspicious activity: Rapid activation detected for ${owner}`);
    }
  }
}

Access Control Monitoring

// Monitor access control changes
class AccessControlMonitor {
  constructor(contract) {
    this.contract = contract;
    this.setupRoleMonitoring();
  }
  
  setupRoleMonitoring() {
    // Monitor for role changes
    this.contract.on('RoleGranted', (role, account, sender, event) => {
      this.logRoleGranted(role, account, sender, event);
    });
    
    this.contract.on('RoleRevoked', (role, account, sender, event) => {
      this.logRoleRevoked(role, account, sender, event);
    });
  }
  
  logRoleGranted(role, account, sender, event) {
    console.log(`Security: Role granted`, {
      role: role.toString(),
      account,
      sender,
      blockNumber: event.blockNumber,
      transactionHash: event.transactionHash
    });
  }
  
  logRoleRevoked(role, account, sender, event) {
    console.log(`Security: Role revoked`, {
      role: role.toString(),
      account,
      sender,
      blockNumber: event.blockNumber,
      transactionHash: event.transactionHash
    });
  }
}

Incident Response

Security Incident Response Plan

  1. Detection: Monitor for suspicious activity
  2. Assessment: Assess the severity of the incident
  3. Containment: Take immediate action to contain the incident
  4. Investigation: Investigate the root cause
  5. Recovery: Implement recovery measures
  6. Prevention: Implement preventive measures

Emergency Procedures

// Emergency response procedures
class EmergencyResponse {
  constructor(contract) {
    this.contract = contract;
    this.emergencyMode = false;
  }
  
  // Activate emergency mode
  activateEmergencyMode() {
    this.emergencyMode = true;
    console.log('Emergency mode activated');
    
    // Stop all non-essential operations
    this.stopNonEssentialOperations();
    
    // Notify security team
    this.notifySecurityTeam();
  }
  
  // Deactivate emergency mode
  deactivateEmergencyMode() {
    this.emergencyMode = false;
    console.log('Emergency mode deactivated');
  }
  
  stopNonEssentialOperations() {
    // Stop non-essential operations
    console.log('Non-essential operations stopped');
  }
  
  notifySecurityTeam() {
    // Notify security team
    console.log('Security team notified');
  }
}

Security Updates

Regular Security Updates

  1. Monitor Security Advisories: Stay updated with security advisories
  2. Update Dependencies: Keep dependencies updated
  3. Security Patches: Apply security patches promptly
  4. Security Reviews: Conduct regular security reviews

Security Communication

  1. Security Notices: Publish security notices when needed
  2. Vulnerability Disclosure: Follow responsible disclosure practices
  3. Security Updates: Communicate security updates to users
  4. Incident Reports: Publish incident reports when appropriate