Micro Garnet Gecko
High
The registerAddress function currently permits any user to add addresses to an existing profile without validating ownership or obtaining approval from the profile owner onchain. This oversight allows unauthorized users to add addresses to someone else’s profile, and it can even be the profile owner address, potentially resulting in addresses being added without the profile owner’s consent. Additionally, the profile owner is unable to remove themselves from the list of addresses, while the profile owner account has already been added when creating a profile, limiting their control over their profile.
In registerAddress, there is no validation check to ensure that only the profile owner or an approved delegate can add addresses to the profile.
The protocol need to check offchain for validation without an onchain validation during the function call.
No response
- Profile Creation: A legitimate user (USER A) creates a profile using createProfile.
- Another legitimate user (USER B) creates a profile using createProfile.
- USER B can use registerAddress to add any address to the USER A profile without the USER A consent, Including USER A self account.
- USER B can continue adding more addresses to the USER A profile, potentially filling it to the maximum allowed number of addresses. This restricts the profile owner from adding legitimate addresses or managing their invites effectively.
USER A (Profile Owner) gradually loses control of their profile’s address list as more unauthorized entries are added to fill the available invite slots, disrupting the Profile Owner’s ability to invite others as they intended.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
import "lib/forge-std/src/Test.sol";
import "../../contracts/EthosProfile.sol";
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
contract EthosProfileTest is Test {
EthosProfile public implementation;
EthosProfile public proxy;
address public userA;
address public userB;
address public userC;
address public userD;
address public owner;
address public admin;
uint256 public expectedSignerPrivateKey = 11111111111;
address public expectedSigner;
address public signatureVerifier;
address public contractAddressManager;
address public weth;
function setUp() public {
// Setup accounts
owner = makeAddr("owner");
admin = makeAddr("admin");
expectedSigner = vm.addr(expectedSignerPrivateKey);//makeAddr(expectedSignerPrivateKey);
signatureVerifier = makeAddr("signatureVerifier");
contractAddressManager = makeAddr("contractAddressManager");
weth = makeAddr("weth");
userA = makeAddr("userA");
userB = makeAddr("userB");
userC = makeAddr("userC");
userD = makeAddr("userD");
// Deploy implementation
implementation = new EthosProfile();
// Deploy proxy
bytes memory initData = abi.encodeWithSelector(
EthosProfile.initialize.selector,
owner,
admin,
expectedSigner,
signatureVerifier,
contractAddressManager,
weth
);
ERC1967Proxy proxyContract = new ERC1967Proxy(
address(implementation),
initData
);
proxy = EthosProfile(address(proxyContract));
vm.startPrank(owner);
proxy.inviteAddress(userA);
proxy.inviteAddress(userB);
}
function testRegisterAddressWithSignature() public {
vm.startPrank(userA);
proxy.createProfile(1);
vm.startPrank(userB);
proxy.createProfile(1);
// admin add invite for user A
vm.startPrank(admin);
proxy.addInvites(userA, 8);
proxy.addInvites(userB, 8);
vm.startPrank(userA);
proxy.inviteAddress(userC);
vm.startPrank(userB);
proxy.inviteAddress(userD);
vm.startPrank(userD);
proxy.createProfile(3);
(, , , uint256 profileId) = proxy.profileStatusByAddress(userD);
uint256 randomValue = 12345; // Random number for entropy
uint256 randomValue2 = 123457; // Random number for entropy
// // Step 1: Compute the message hash using `_keccakForRegisterAddress`
bytes32 messageHash = keccak256(abi.encodePacked(userD, profileId, randomValue));
(uint8 v, bytes32 r, bytes32 s) = vm.sign(expectedSignerPrivateKey, messageHash);
bytes memory signature = abi.encodePacked(r, s, v);
bytes32 messageHash2 = keccak256(abi.encodePacked(userD, profileId, randomValue2));
( v, r, s) = vm.sign(expectedSignerPrivateKey, messageHash2);
bytes memory signature2 = abi.encodePacked(r, s, v);
// Step 3: Ensure the test contract can validate the signature and register the address
vm.startPrank(userA);
proxy.registerAddress(userD, profileId, randomValue, signature);
proxy.registerAddress(userD, profileId, randomValue, signature2);
// vm.stopPrank();
}
}
Introduce ownership or delegate checks in the registerAddress function to verify that addressStr is approved by the profile’s owner.