msc-smart-contract-auditing/vulnerable-functions-base huggingface dataset:
Vulnerability: RocketDAOProposals - Unpredictable behavior due to short vote delay
Severity: high

Description:
A proposal can be voted and passed when it enters the `ACTIVE` state. Voting starts when the current `block.number` is greater than the `startBlock` configured in the proposal (up until the endBlock). The requirement for the `startBlock` is to be at least greater than `block.number` when the proposal is submitted.\\n```\\nrequire(\\_startBlock > block.number, "Proposal start block must be in the future");\\nrequire(\\_durationBlocks > 0, "Proposal cannot have a duration of 0 blocks");\\nrequire(\\_expiresBlocks > 0, "Proposal cannot have a execution expiration of 0 blocks");\\nrequire(\\_votesRequired > 0, "Proposal cannot have a 0 votes required to be successful");\\n```\\n\\nThe default vote delay configured in the system is `1` block.\\n```\\nsetSettingUint('proposal.vote.delay.blocks', 1);                 // How long before a proposal can be voted on after it is created. Approx. Next Block\\n```\\n\\nA vote is immediately passed when the required quorum is reached which allows it to be executed. This means that a group that is holding enough voting power can propose a change, wait for two blocks (block.number (of time of proposal creation) + configuredDelay (1) + 1 (for ACTIVE state), then vote and execute for the proposal to pass for it to take effect almost immediately after only 2 blocks (<30seconds).\\nSettings can be changed after 30 seconds which might be unpredictable for other DAO members and not give them enough time to oppose and leave the DAO.

Impact:

Recommended mitigation:
The underlying issue is that users of the system can't be sure what the behavior of a function call will be, and this is because the behavior can change after two blocks. The only guarantee is that users can be sure the settings don't change for the next block if no proposal is active.\\nWe recommend giving the user advance notice of changes with a delay. For example, all upgrades should require two steps with a mandatory time window between them. The first step merely broadcasts to users that a particular change is coming, and the second step commits that change after a suitable waiting period.
Vulnerability: RocketStorage - Risk concentration by giving all registered contracts permissions to change any settings in RocketStorage  Acknowledged
Severity: high

Description:
The ACL for changing settings in the centralized `RocketStorage` allows any registered contract (listed under contract.exists) to change settings that belong to other parts of the system.\\nThe concern is that if someone finds a way to add their malicious contract to the registered contact list, they will override any setting in the system. The storage is authoritative when checking certain ACLs. Being able to set any value might allow an attacker to gain control of the complete system. Allowing any contract to overwrite other contracts' settings dramatically increases the attack surface.\\n```\\nmodifier onlyLatestRocketNetworkContract() {\\n    // The owner and other contracts are only allowed to set the storage upon deployment to register the initial contracts/settings, afterwards their direct access is disabled\\n    if (boolStorage[keccak256(abi.encodePacked("contract.storage.initialised"))] == true) {\\n        // Make sure the access is permitted to only contracts in our Dapp\\n        require(boolStorage[keccak256(abi.encodePacked("contract.exists", msg.sender))], "Invalid or outdated network contract");\\n    }\\n    \\_;\\n}\\n```\\n\\n```\\nfunction setAddress(bytes32 \\_key, address \\_value) onlyLatestRocketNetworkContract override external {\\n    addressStorage[\\_key] = \\_value;\\n}\\n\\n/// @param \\_key The key for the record\\nfunction setUint(bytes32 \\_key, uint \\_value) onlyLatestRocketNetworkContract override external {\\n    uIntStorage[\\_key] = \\_value;\\n}\\n```\\n

Impact:

Recommended mitigation:
Resolution\\nThe client provided the following statement:\\nWe've looked at adding access control contracts using namespaces, but the increase in gas usage would be significant and could hinder upgrades.\\nAllow contracts to only change settings related to their namespace.
Vulnerability: RocketDAOProposals - require a minimum participation quorum for DAO proposals
Severity: medium

Description:
If the DAO falls below the minimum viable membership threshold, voting for proposals still continues as DAO proposals do not require a minimum participation quorum. In the worst case, this would allow the last standing DAO member to create a proposal that would be passable with only one vote even if new members would be immediately ready to join via the recovery mode (which has its own risks) as the minimum votes requirement for proposals is set as `>0`.\\n```\\nrequire(\\_votesRequired > 0, "Proposal cannot have a 0 votes required to be successful");\\n```\\n\\n```\\nfunction propose(string memory \\_proposalMessage, bytes memory \\_payload) override public onlyTrustedNode(msg.sender) onlyLatestContract("rocketDAONodeTrustedProposals", address(this)) returns (uint256) {\\n    // Load contracts\\n    RocketDAOProposalInterface daoProposal = RocketDAOProposalInterface(getContractAddress('rocketDAOProposal'));\\n    RocketDAONodeTrustedInterface daoNodeTrusted = RocketDAONodeTrustedInterface(getContractAddress('rocketDAONodeTrusted'));\\n    RocketDAONodeTrustedSettingsProposalsInterface rocketDAONodeTrustedSettingsProposals = RocketDAONodeTrustedSettingsProposalsInterface(getContractAddress("rocketDAONodeTrustedSettingsProposals"));\\n    // Check this user can make a proposal now\\n    require(daoNodeTrusted.getMemberLastProposalBlock(msg.sender).add(rocketDAONodeTrustedSettingsProposals.getCooldown()) <= block.number, "Member has not waited long enough to make another proposal");\\n    // Record the last time this user made a proposal\\n    setUint(keccak256(abi.encodePacked(daoNameSpace, "member.proposal.lastblock", msg.sender)), block.number);\\n    // Create the proposal\\n    return daoProposal.add(msg.sender, 'rocketDAONodeTrustedProposals', \\_proposalMessage, block.number.add(rocketDAONodeTrustedSettingsProposals.getVoteDelayBlocks()), rocketDAONodeTrustedSettingsProposals.getVoteBlocks(), rocketDAONodeTrustedSettingsProposals.getExecuteBlocks(), daoNodeTrusted.getMemberQuorumVotesRequired(), \\_payload);\\n}\\n```\\n\\nSidenote: Since a proposals acceptance quorum is recorded on proposal creation, this may lead to another scenario where proposals acceptance quorum may never be reached if members leave the DAO. This would require a re-submission of the proposal.

Impact:

Recommended mitigation:
Do not accept proposals if the member count falls below the minimum DAO membercount threshold.
Vulnerability: RocketDAONodeTrustedUpgrade - inconsistent upgrade blacklist
Severity: medium

Description:
`upgradeContract` defines a hardcoded list of contracts that cannot be upgraded because they manage their own settings (statevars) or they hold value in the system.\\nthe list is hardcoded and cannot be extended when new contracts are added via `addcontract`. E.g. what if another contract holding value is added to the system? This would require an upgrade of the upgrade contract to update the whitelist (gas hungry, significant risk of losing access to the upgrade mechanisms if a bug is being introduced).\\na contract named `rocketPoolToken` is blacklisted from being upgradeable but the system registers no contract called `rocketPoolToken`. This may be an oversight or artifact of a previous iteration of the code. However, it may allow a malicious group of nodes to add a contract that is not yet in the system which cannot be removed anymore as there is no `removeContract` functionality and `upgradeContract` to override the malicious contract will fail due to the blacklist.\\nNote that upgrading `RocketTokenRPL` requires an account balance migration as contracts in the system may hold value in `RPL` (e.g. a lot in AuctionManager) that may vanish after an upgrade. The contract is not exempt from upgrading. A migration may not be easy to perform as the system cannot be paused to e.g. snapshot balances.\\n```\\nfunction \\_upgradeContract(string memory \\_name, address \\_contractAddress, string memory \\_contractAbi) internal {\\n    // Check contract being upgraded\\n    bytes32 nameHash = keccak256(abi.encodePacked(\\_name));\\n    require(nameHash != keccak256(abi.encodePacked("rocketVault")),        "Cannot upgrade the vault");\\n    require(nameHash != keccak256(abi.encodePacked("rocketPoolToken")),    "Cannot upgrade token contracts");\\n    require(nameHash != keccak256(abi.encodePacked("rocketTokenRETH")),     "Cannot upgrade token contracts");\\n    require(nameHash != keccak256(abi.encodePacked("rocketTokenNETH")), "Cannot upgrade token contracts");\\n    require(nameHash != keccak256(abi.encodePacked("casperDeposit")),      "Cannot upgrade the casper deposit contract");\\n    // Get old contract address & check contract exists\\n```\\n

Impact:

Recommended mitigation:
Consider implementing a whitelist of contracts that are allowed to be upgraded instead of a more error-prone blacklist of contracts that cannot be upgraded.\\nProvide documentation that outlines what contracts are upgradeable and why.\\nCreate a process to verify the blacklist before deploying/operating the system.\\nPlan for migration paths when upgrading contracts in the system\\nAny proposal that reaches the upgrade contract must be scrutinized for potential malicious activity (e.g. as any registered contract can directly modify storage or may contain subtle backdoors. Upgrading without performing a thorough security inspection may easily put the DAO at risk)
Vulnerability: RocketMinipoolStatus - DAO Membership changes can result in votes getting stuck
Severity: medium

Description:
Changes in the DAO's trusted node members are reflected in the `RocketDAONodeTrusted.getMemberCount()` function. When compared with the vote on consensus threshold, a DAO-driven decision is made, e.g., when updating token price feeds and changing Minipool states.\\nEspecially in the early phase of the DAO, the functions below can get stuck as execution is restricted to DAO members who have not voted yet. Consider the following scenario:\\nThe DAO consists of five members\\nTwo members vote to make a Minipool withdrawable\\nThe other three members are inactive, the community votes, and they get kicked from the DAO\\nThe two remaining members have no way to change the Minipool state now. All method calls to trigger the state update fails because the members have already voted before.\\nNote: votes of members that are kicked/leave are still count towards the quorum!\\nSetting a Minipool into the withdrawable state:\\n```\\nRocketDAONodeTrustedInterface rocketDAONodeTrusted = RocketDAONodeTrustedInterface(getContractAddress("rocketDAONodeTrusted"));\\nif (calcBase.mul(submissionCount).div(rocketDAONodeTrusted.getMemberCount()) >= rocketDAOProtocolSettingsNetwork.getNodeConsensusThreshold()) {\\n    setMinipoolWithdrawable(\\_minipoolAddress, \\_stakingStartBalance, \\_stakingEndBalance);\\n}\\n```\\n\\nSubmitting a block's network balances:\\n```\\nRocketDAONodeTrustedInterface rocketDAONodeTrusted = RocketDAONodeTrustedInterface(getContractAddress("rocketDAONodeTrusted"));\\nif (calcBase.mul(submissionCount).div(rocketDAONodeTrusted.getMemberCount()) >= rocketDAOProtocolSettingsNetwork.getNodeConsensusThreshold()) {\\n    updateBalances(\\_block, \\_totalEth, \\_stakingEth, \\_rethSupply);\\n}\\n```\\n\\nSubmitting a block's RPL price information:\\n```\\nRocketDAONodeTrustedInterface rocketDAONodeTrusted = RocketDAONodeTrustedInterface(getContractAddress("rocketDAONodeTrusted"));\\nif (calcBase.mul(submissionCount).div(rocketDAONodeTrusted.getMemberCount()) >= rocketDAOProtocolSettingsNetwork.getNodeConsensusThreshold()) {\\n    updatePrices(\\_block, \\_rplPrice);\\n}\\n```\\n

Impact:

Recommended mitigation:
Resolution\\nThis issue has been fixed in PR https://github.com/ConsenSys/rocketpool-audit-2021-03/issues/204 by introducing a public method that allows anyone to manually trigger a DAO consensus threshold check and a subsequent balance update in case the issue's example scenario occurs.\\nThe conditional check and update of price feed information, Minipool state transition, etc., should be externalized into a separate public function. This function is also called internally in the existing code. In case the DAO gets into the scenario above, anyone can call the function to trigger a reevaluation of the condition with updated membership numbers and thus get the process unstuck.
Vulnerability: RocketMiniPoolDelegate - on destroy() leftover ETH is sent to RocketVault where it cannot be recovered
Severity: medium

Description:
When destroying the `MiniPool`, leftover `ETH` is sent to the `RocketVault`. Since `RocketVault` has no means to recover “unaccounted” `ETH` (not deposited via depositEther), funds forcefully sent to the vault will end up being locked.\\n```\\n// Destroy the minipool\\nfunction destroy() private {\\n    // Destroy minipool\\n    RocketMinipoolManagerInterface rocketMinipoolManager = RocketMinipoolManagerInterface(getContractAddress("rocketMinipoolManager"));\\n    rocketMinipoolManager.destroyMinipool();\\n    // Self destruct & send any remaining ETH to vault\\n    selfdestruct(payable(getContractAddress("rocketVault")));\\n}\\n```\\n

Impact:

Recommended mitigation:
Implement means to recover and reuse `ETH` that was forcefully sent to the contract by `MiniPool` instances.
Vulnerability: RocketDAO - personally identifiable member information (PII) stored on-chain  Acknowledged
Severity: medium

Description:
Like a DAO user's e-mail address, PII is stored on-chain and can, therefore, be accessed by anyone. This may allow de-pseudonymize users (and correlate Ethereum addresses to user email addresses) and be used for spamming or targeted phishing campaigns putting the DAO users at risk.\\nrocketpool-go-2.5-Tokenomics/dao/trustednode/dao.go:L173-L183\\n```\\n// Return\\nreturn MemberDetails{\\n    Address: memberAddress,\\n    Exists: exists,\\n    ID: id,\\n    Email: email,\\n    JoinedBlock: joinedBlock,\\n    LastProposalBlock: lastProposalBlock,\\n    RPLBondAmount: rplBondAmount,\\n    UnbondedValidatorCount: unbondedValidatorCount,\\n}, nil\\n```\\n\\n```\\nfunction getMemberEmail(address \\_nodeAddress) override public view returns (string memory) {\\n    return getString(keccak256(abi.encodePacked(daoNameSpace, "member.email", \\_nodeAddress))); \\n}\\n```\\n

Impact:

Recommended mitigation:
Avoid storing PII on-chain where it is readily available for anyone.
Vulnerability: RocketPoolMinipool - should check for address(0x0)
Severity: medium

Description:
The two implementations for `getContractAddress()` in `Minipool/Delegate` are not checking whether the requested contract's address was ever set before. If it were never set, the method would return `address(0x0)`, which would silently make all delegatecalls succeed without executing any code. In contrast, `RocketBase.getContractAddress()` fails if the requested contract is not known.\\nIt should be noted that this can happen if `rocketMinipoolDelegate` is not set in global storage, or it was cleared afterward, or if `_rocketStorageAddress` points to a contract that implements a non-throwing fallback function (may not even be storage at all).\\nMissing checks\\n```\\nfunction getContractAddress(string memory \\_contractName) private view returns (address) {\\n    return rocketStorage.getAddress(keccak256(abi.encodePacked("contract.address", \\_contractName)));\\n}\\n```\\n\\n```\\nfunction getContractAddress(string memory \\_contractName) private view returns (address) {\\n    return rocketStorage.getAddress(keccak256(abi.encodePacked("contract.address", \\_contractName)));\\n}\\n```\\n\\nChecks implemented\\n```\\nfunction getContractAddress(string memory \\_contractName) internal view returns (address) {\\n    // Get the current contract address\\n    address contractAddress = getAddress(keccak256(abi.encodePacked("contract.address", \\_contractName)));\\n    // Check it\\n    require(contractAddress != address(0x0), "Contract not found");\\n    // Return\\n    return contractAddress;\\n}\\n```\\n

Impact:

Recommended mitigation:
Resolution\\nAddressed in branch `rp3.0-updates` (rocket-pool/[email protected]b424ca1) by changing requiring that the contract address is not `0x0`.\\nSimilar to `RocketBase.getContractAddress()` require that the contract is set.
Vulnerability: RocketDAONodeTrustedAction - ambiguous event emitted in actionChallengeDecide
Severity: low

Description:
`actionChallengeDecide` succeeds and emits `challengeSuccess=False` in case the challenged node defeats the challenge. It also emits the same event if another node calls `actionChallengeDecided` before the refute window passed. This ambiguity may make a defeated challenge indistinguishable from a challenge that was attempted to be decided too early (unless the component listening for the event also checks the refute window).\\n```\\n    // Allow the challenged member to refute the challenge at anytime. If the window has passed and the challenge node does not run this method, any member can decide the challenge and eject the absent member\\n    // Is it the node being challenged?\\n    if(\\_nodeAddress == msg.sender) {\\n        // Challenge is defeated, node has responded\\n        deleteUint(keccak256(abi.encodePacked(daoNameSpace, "member.challenged.block", \\_nodeAddress)));\\n    }else{\\n        // The challenge refute window has passed, the member can be ejected now\\n        if(getUint(keccak256(abi.encodePacked(daoNameSpace, "member.challenged.block", \\_nodeAddress))).add(rocketDAONodeTrustedSettingsMembers.getChallengeWindow()) < block.number) {\\n            // Node has been challenged and failed to respond in the given window, remove them as a member and their bond is burned\\n            \\_memberRemove(\\_nodeAddress);\\n            // Challenge was successful\\n            challengeSuccess = true;\\n        }\\n    }\\n    // Log it\\n    emit ActionChallengeDecided(\\_nodeAddress, msg.sender, challengeSuccess, block.timestamp);\\n}\\n```\\n

Impact:

Recommended mitigation:
Avoid ambiguities when emitting events. Consider throwing an exception in the else branch if the refute window has not passed yet (minimal gas savings; it's clear that the call failed; other components can rely on the event only being emitted if there was a decision.
Vulnerability: RocketDAOProtocolProposals, RocketDAONodeTrustedProposals - unused enum ProposalType
Severity: low

Description:
The enum `ProposalType` is defined but never used.\\n```\\nenum ProposalType {\\n    Invite,             // Invite a registered node to join the trusted node DAO\\n    Leave,              // Leave the DAO\\n    Replace,            // Replace a current trusted node with a new registered node, they take over their bond\\n    Kick,               // Kick a member from the DAO with optional penalty applied to their RPL deposit\\n    Setting             // Change a DAO setting (Quorum threshold, RPL deposit size, voting periods etc)\\n}\\n```\\n\\n```\\nenum ProposalType {\\n    Setting             // Change a DAO setting (Node operator min/max fees, inflation rate etc)\\n}\\n```\\n

Impact:

Recommended mitigation:
Remove unnecessary code.
Vulnerability: RocketDaoNodeTrusted - Unused events
Severity: low

Description:
The `MemberJoined` `MemberLeave` events are not used within `RocketDaoNodeTrusted`.\\n```\\n// Events\\nevent MemberJoined(address indexed \\_nodeAddress, uint256 \\_rplBondAmount, uint256 time); \\nevent MemberLeave(address indexed \\_nodeAddress, uint256 \\_rplBondAmount, uint256 time);\\n```\\n

Impact:

Recommended mitigation:
Consider removing the events. Note: `RocketDAONodeTrustedAction` is emitting `ActionJoin` and `ActionLeave` event.s
Vulnerability: RocketDAOProposal - expired, and defeated proposals can be canceled
Severity: low

Description:
The `RocketDAOProposal.getState` function defaults a proposal's state to `ProposalState.Defeated`. While this fallback can be considered secure, the remaining code does not perform checks that prevent defeated proposals from changing their state. As such, a user can transition a proposal that is `Expired` or `Defeated` to `Cancelled` by using the `RocketDAOProposal.cancel` function. This can be used to deceive users and potentially bias future votes.\\nThe method emits an event that might trigger other components to perform actions.\\n```\\n} else {\\n    // Check the votes, was it defeated?\\n    // if (votesFor <= votesAgainst || votesFor < getVotesRequired(\\_proposalID))\\n    return ProposalState.Defeated;\\n}\\n```\\n\\n```\\nfunction cancel(address \\_member, uint256 \\_proposalID) override public onlyDAOContract(getDAO(\\_proposalID)) {\\n    // Firstly make sure this proposal that hasn't already been executed\\n    require(getState(\\_proposalID) != ProposalState.Executed, "Proposal has already been executed");\\n    // Make sure this proposal hasn't already been successful\\n    require(getState(\\_proposalID) != ProposalState.Succeeded, "Proposal has already succeeded");\\n    // Only allow the proposer to cancel\\n    require(getProposer(\\_proposalID) == \\_member, "Proposal can only be cancelled by the proposer");\\n    // Set as cancelled now\\n    setBool(keccak256(abi.encodePacked(daoProposalNameSpace, "cancelled", \\_proposalID)), true);\\n    // Log it\\n    emit ProposalCancelled(\\_proposalID, \\_member, block.timestamp);\\n}\\n```\\n

Impact:

Recommended mitigation:
Preserve the true outcome. Do not allow to cancel proposals that are already in an end-state like `canceled`, `expired`, `defeated`.
Vulnerability: RocketDAOProposal - preserve the proposals correct state after expiration
Severity: low

Description:
The state of proposals is resolved to give a preference to a proposal being `expired` over the actual result which may be `defeated`. The preference for a proposal's status is checked in order: `cancelled? -> executed? -> `expired`? -> succeeded? -> pending? -> active? -> `defeated` (default)`\\n```\\nif (getCancelled(\\_proposalID)) {\\n    // Cancelled by the proposer?\\n    return ProposalState.Cancelled;\\n    // Has it been executed?\\n} else if (getExecuted(\\_proposalID)) {\\n    return ProposalState.Executed;\\n    // Has it expired?\\n} else if (block.number >= getExpires(\\_proposalID)) {\\n    return ProposalState.Expired;\\n    // Vote was successful, is now awaiting execution\\n} else if (votesFor >= getVotesRequired(\\_proposalID)) {\\n    return ProposalState.Succeeded;\\n    // Is the proposal pending? Eg. waiting to be voted on\\n} else if (block.number <= getStart(\\_proposalID)) {\\n    return ProposalState.Pending;\\n    // The proposal is active and can be voted on\\n} else if (block.number <= getEnd(\\_proposalID)) {\\n    return ProposalState.Active;\\n} else {\\n    // Check the votes, was it defeated?\\n    // if (votesFor <= votesAgainst || votesFor < getVotesRequired(\\_proposalID))\\n    return ProposalState.Defeated;\\n}\\n```\\n

Impact:

Recommended mitigation:
consider checking for `voteAgainst` explicitly and return `defeated` instead of `expired` if a proposal was `defeated` and is queried after expiration. Preserve the actual proposal result.