During initialization of a InitialETHCrowdfund, we have someone called initialContributor. This is an address that will be accounted for an initial contribution to the crowdfund, if set. The point of this initial contributor is to kickstart the crowdfund with some ETH.
uint96 initialContribution = msg.value.safeCastUint256ToUint96();
if (initialContribution > 0) {
// If this contract has ETH, either passed in during deployment or
// pre-existing, credit it to the `initialContributor`.
_contribute(
crowdfundOpts.initialContributor,
crowdfundOpts.initialDelegate,
initialContribution,
0,
""
);
}
As you can see the comment states: "If this contract has ETH, either passed in during deployment or pre-existing, credit it to the initialContributor."
However, the initial contributor is only credited with a contribution if he passed in msg.value. Nowhere do we check if the contract already has a balance. If it has a balance it should be credited to the initial contributor as well.
Proof of Concept
Example:
Alice wants to create a Party and a crowdfund for her Party.
Before creation, she decides to send 1 ETH to the crowdfund to get it started.
initialize is executed and the original 1 ETH doesn't get credited to anyone, effectively getting stuck.
Tools Used
Manual Review
Recommended Mitigation Steps
Add the following inside initialize.
uint96 initialContribution = msg.value.safeCastUint256ToUint96() + address(this).balance;
if (initialContribution > 0) {
// If this contract has ETH, either passed in during deployment or
// pre-existing, credit it to the `initialContributor`.
_contribute(
crowdfundOpts.initialContributor,
crowdfundOpts.initialDelegate,
initialContribution,
0,
""
);
}
Lines of code
https://github.com/code-423n4/2023-10-party/blob/b23c65d62a20921c709582b0b76b387f2bb9ebb5/contracts/crowdfund/InitialETHCrowdfund.sol#L140-L151
Vulnerability details
Impact
During initialization of a
InitialETHCrowdfund
, we have someone calledinitialContributor
. This is an address that will be accounted for an initial contribution to the crowdfund, if set. The point of this initial contributor is to kickstart the crowdfund with some ETH.As you can see the comment states: "If this contract has ETH, either passed in during deployment or pre-existing, credit it to the
initialContributor
."However, the initial contributor is only credited with a contribution if he passed in
msg.value
. Nowhere do we check if the contract already has a balance. If it has a balance it should be credited to the initial contributor as well.Proof of Concept
Example:
initialize
is executed and the original 1 ETH doesn't get credited to anyone, effectively getting stuck.Tools Used
Manual Review
Recommended Mitigation Steps
Add the following inside
initialize
.Assessed type
Invalid Validation