• YouTube Channel
  • System Status
  • VS Code Extension
  • Struct with Mapping Deletion

    Overview

    What is the Struct with Mapping Deletion vulnerability?

    In Solidity, as in several other programming languages, structs can be used to organize and store data. If a struct contains a mapping as a member, the delete keyword will not clear the associated mapping, so care must be taken if this is the intent of the developer.

    Further reading: Solidity Documentation: Structs

    Technical example of vulnerable code

      // SPDX-License-Identifier: Unlicense
      pragma solidity ^0.8.0;
    
      contract Membership {
          struct MemberProfile {
              string name;
              uint256 joinDate;
              mapping(uint256 => bool) monthlyDuesPaid; // Mapping: month => paid/not
          }
    
          mapping(address => MemberProfile) public memberProfiles;
    
          // Function to add or update a member's profile
          function setMemberProfile(address member, string memory name, uint256 joinDate) public {
              memberProfiles[member].name = name;
              memberProfiles[member].joinDate = joinDate;
          }
    
          // Record a monthly dues payment
          function recordDuesPayment(address member, uint256 month) public {
              memberProfiles[member].monthlyDuesPaid[month] = true;
          }
    
          // Incorrectly attempting to reset a member's profile using `delete`
          function removeMember(address member) public {
              // Developer expects this to clear the member's profile and dues records
              delete memberProfiles[member];
          }
      }
    

    In the example above, contract Membership represents logic for managing members as part of some broader decentralized application. The contract defines a struct MemberProfile that contains a mapping member to track dues paid for membership in the organization. The function removeMember() attempts to clear this data using the delete keyword, which will not actually clear the mapping data. If the mapping data were used in some other context in the decentralized application, e.g. to confirm eligibility for some benefit, they could still potentially be used for a member that was removed.

    Technical example of how to fix the vulnerability

      // SPDX-License-Identifier: Unlicense
      pragma solidity ^0.8.0;
    
      contract MembershipUpdated {
          struct MemberProfile {
              string name;
              uint256 joinDate;
          }
    
          mapping(address => MemberProfile) public memberProfiles;
    
          // Dues payment now tracked in a distinct mapping
          mapping(address => mapping(uint256 => bool)) monthlyDuesPaid;
    
          // Function to add or update a member's profile
          function setMemberProfile(address member, string memory name, uint256 joinDate) public {
              memberProfiles[member].name = name;
              memberProfiles[member].joinDate = joinDate;
          }
    
          // Record a monthly dues payment
          function recordDuesPayment(address member, uint256 month) public {
              monthlyDuesPaid[member][month] = true;
          }
    
          // Delete the struct that no longer contains a mapping
          function removeMember(address member) public {
              delete memberProfiles[member];
          }
      }
    
    

    In the revised example above, contract MembershipUpdated has changed the manner in which member information and dues payments are stored: dues payment info is now in a separate mapping monthlyDuesPaid, and the MemberProfile struct no longer contains a mapping, so the delete keyword in function removeMember() will now delete the struct data.