Beginner FriendlyFoundryGameFi
100 EXP
View results
Submission Details
Severity: medium
Valid

Improper Implementation of access control for MartenitsaEvent::joinEvent

Summary

According to the project documentation, producers should not be able to join the special event. However, it was found that producers are currently able to join the special event, violating the intended access control.

Vulnerability Details

The vulnerability stems from improper access control checks within the special event joining mechanism. The current implementation fails to properly validate and restrict producers from participating in the special event. This allows producers to bypass the intended restrictions and gain unauthorized access to the event. The MartenitsaEvent contract extends the MartenitsaToken contract, enabling the MartenitsaEvent contract to possess its own producers array and isProducer mapping. Consequently, it operates independently of the storage variables within the deployed MartenitsaToken contract, where all producers are typically stored and mapped.

@> contract MartenitsaEvent is MartenitsaToken {
HealthToken private _healthToken;
function joinEvent() external {
require(block.timestamp < eventEndTime, "Event has ended");
require(!_participants[msg.sender], "You have already joined the event");
@> require(!isProducer[msg.sender], "Producers are not allowed to participate");
require(_healthToken.balanceOf(msg.sender) >= healthTokenRequirement, "Insufficient HealthToken balance");
_participants[msg.sender] = true;
participants.push(msg.sender);
emit ParticipantJoined(msg.sender);
(bool success) = _healthToken.transferFrom(msg.sender, address(this), healthTokenRequirement);
require(success, "The transfer is not successful");
_addProducer(msg.sender);
}
}

Impact

MartenitsaToken producers are able to access the special event which is not the intended system design.

POC

Below you can see a POC that shows how this can happen:

function testProducerJoinEvent() public activeEvent eligibleForReward {
vm.startPrank(bob);
marketplace.collectReward();
healthToken.transfer(address(jack), 1 ether);
vm.stopPrank();
vm.startPrank(jack);
assert(martenitsaEvent.isProducer(jack) == true);
healthToken.approve(address(martenitsaEvent), 10 ** 18);
martenitsaEvent.joinEvent();
vm.stopPrank();
}

Tools Used

VS Code, Foundry, Manual Review

Recommendations

The inheritance should be removed and the main MartenitsaToken contract should be used for access control

- contract MartenitsaEvent is MartenitsaToken {
+ contract MartenitsaEvent {
HealthToken private _healthToken;
+ MartenitsaToken public martenitsaToken;
.......
constructor(address healthToken) onlyOwner {
_healthToken = HealthToken(healthToken);
+ martenitsaToken = MartenitsaToken(_martenitsaToken);
}
..........
function joinEvent() external {
require(block.timestamp < eventEndTime, "Event has ended");
require(!_participants[msg.sender], "You have already joined the event");
- require(!isProducer[msg.sender], "Producers are not allowed to participate");
+ require(!martenitsaToken.isProducer(msg.sender), "Producers are not allowed to participate");
require(_healthToken.balanceOf(msg.sender) >= healthTokenRequirement, "Insufficient HealthToken balance");
_participants[msg.sender] = true;
participants.push(msg.sender);
emit ParticipantJoined(msg.sender);
(bool success) = _healthToken.transferFrom(msg.sender, address(this), healthTokenRequirement);
require(success, "The transfer is not successful");
_addProducer(msg.sender);
}
}
Updates

Lead Judging Commences

bube Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

MartenitsaToken and MartenitsaEvent have different addresses

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.