Open c4-bot-5 opened 1 month ago
Since approvals
and disapprovals
aren't cleared, I considered a possible scenario where price feeds couldn't approve a proposal after a previous proposal was executed because of this check and this assignment. But the ++_usdProposalId increment on proposeUSDPrice()
solves any potential issues.
This is relevant for similar issues #31, #32, #33, #88, #215, #391
A POC is provided as here as well. Add this code to tests/managers/LockManager/approveUSDPrice.test.ts
and run the tests:
describe("second proposals failure", () => {
beforeEach(async () => {
// Propose
const setUSDThresholdsTxHash =
await testContracts.lockManager.contract.write.setUSDThresholds([3, 3], { account: admin });
await assertTxSuccess({ txHash: setUSDThresholdsTxHash });
let txHash = await testContracts.lockManager.contract.write.proposeUSDPrice(
[price, [zeroAddress]],
{
account: priceFeed1,
}
);
await assertTxSuccess({ txHash });
// Cast two more votes to approve the proposal and execute it
txHash = await testContracts.lockManager.contract.write.approveUSDPrice([price], {
account: priceFeed2,
});
await assertTxSuccess({ txHash });
txHash = await testContracts.lockManager.contract.write.approveUSDPrice([price], {
account: priceFeed3,
});
const txReceipt = await assertTxSuccess({ txHash });
assertTransactionEvents({
abi: testContracts.lockManager.contract.abi,
logs: txReceipt.logs,
expectedEvents: [
{
eventName: "ApprovedUSDPrice",
args: {
_approver: priceFeed3,
},
},
],
});
await assertApproveUSDPriceSuccess({
tokenPrices: [{ tokenContractAddress: zeroAddress, price }],
});
});
it("doesn't fail when trying to propose or vote on a second proposal", async () => {
let txHash = await testContracts.lockManager.contract.write.proposeUSDPrice(
[price, [zeroAddress]],
{
account: priceFeed1,
}
);
await assertTxSuccess({ txHash });
txHash = await testContracts.lockManager.contract.write.approveUSDPrice([price], {
account: priceFeed2,
});
await assertTxSuccess({ txHash });
});
});
Lines of code
https://github.com/code-423n4/2024-05-munchables/blob/57dff486c3cd905f21b330c2157fe23da2a4807d/src/interfaces/ILockManager.sol#L65-L66 https://github.com/code-423n4/2024-05-munchables/blob/57dff486c3cd905f21b330c2157fe23da2a4807d/src/managers/LockManager.sol#L161 https://github.com/code-423n4/2024-05-munchables/blob/57dff486c3cd905f21b330c2157fe23da2a4807d/src/managers/LockManager.sol#L238 https://github.com/code-423n4/2024-05-munchables/blob/57dff486c3cd905f21b330c2157fe23da2a4807d/src/managers/LockManager.sol#L525
Vulnerability details
In Lockmanager.sol when creating a new
update proposal
to propose a new USD price for an asset in proposeUSDPrice(), in disapproveUSDPrice() when the disapproval threshold has been reached and in _execUSDPriceUpdate() when the approval threshold for the new price has been reached. The structusdUpdateProposal
is reset to its default values using thedelete
keyword.proposeUSDPrice()
disapproveUSDPrice()
_execUSDPriceUpdate()
The
issue
here is that this struct usdUpdateProposal has a mapping in it and in solidity usingdelete
on a struct with mapping in it will lead to storage corruption and other unexpected resultsImpact
The mapping in the struct
usdUpdateProposal
will not be properly deleted leading to unwanted issuesTools Used
Manual Review
Recommended Mitigation Steps
Instead of deleting the whole struct simply reset the
proposer
in the struct to address zero after executing the update or rejecting it.Assessed type
Error