msc-smart-contract-auditing/vulnerable-functions-base huggingface dataset:
Vulnerability: ERC20Lockable - inconsistent locking status
Severity: low

Description:
`Vega_Token.is_tradable()` will incorrectly return `false` if the token is never manually unlocked by the owner but `unlock_time` has passed, which will automatically unlock trading.\\n```\\n/\\*\\*\\n \\* @dev locked status, only applicable before unlock\\_date\\n \\*/\\nbool public \\_is\\_locked = true;\\n\\n/\\*\\*\\n \\* @dev Modifier that only allows function to run if either token is unlocked or time has expired.\\n \\* Throws if called while token is locked.\\n \\*/\\nmodifier onlyUnlocked() {\\n    require(!\\_is\\_locked || now > unlock\\_date);\\n    \\_;\\n}\\n\\n/\\*\\*\\n \\* @dev Internal function that unlocks token. Can only be ran before expiration (give that it's irrelevant after)\\n \\*/\\nfunction \\_unlock() internal {\\n    require(now <= unlock\\_date);\\n    \\_is\\_locked = false;\\n```\\n

Impact:

Recommended mitigation:
declare `_is_locked` as `private` instead of `public`\\ncreate a getter method that correctly returns the locking status\\n```\\nfunction \\_isLocked() internal view {\\n       return !\\_is\\_locked || now > unlock\\_date;\\n}\\n```\\n\\nmake `modifier onlyUnlocked()` use the newly created getter (_isLocked())\\nmake `Vega_Token.is_tradeable()` use the newly created getter (_isLocked())\\n`_unlock()` should raise an errorcondition when called on an already unlocked contract\\nit could make sense to emit a “contract hast been unlocked” event for auditing purposes
Vulnerability: Merkle - The implementation does not enforce inclusion of leaf nodes.
Severity: medium

Description:
A observation with the current Merkle tree implementation is that it may be possible to validate nodes other than leaves. This is done by providing `checkMembership` with a reference to a hash within the tree, rather than a leaf.\\n```\\n/\\*\\*\\n \\* @notice Checks that a leaf hash is contained in a root hash\\n \\* @param leaf Leaf hash to verify\\n \\* @param index Position of the leaf hash in the Merkle tree\\n \\* @param rootHash Root of the Merkle tree\\n \\* @param proof A Merkle proof demonstrating membership of the leaf hash\\n \\* @return True, if the leaf hash is in the Merkle tree; otherwise, False\\n\\*/\\nfunction checkMembership(bytes32 leaf, uint256 index, bytes32 rootHash, bytes memory proof)\\n    internal\\n    pure\\n    returns (bool)\\n{\\n    require(proof.length % 32 == 0, "Length of Merkle proof must be a multiple of 32");\\n\\n    bytes32 proofElement;\\n    bytes32 computedHash = leaf;\\n    uint256 j = index;\\n    // Note: We're skipping the first 32 bytes of `proof`, which holds the size of the dynamically sized `bytes`\\n    for (uint256 i = 32; i <= proof.length; i += 32) {\\n        // solhint-disable-next-line no-inline-assembly\\n        assembly {\\n            proofElement := mload(add(proof, i))\\n        }\\n        if (j % 2 == 0) {\\n            computedHash = keccak256(abi.encodePacked(computedHash, proofElement));\\n        } else {\\n            computedHash = keccak256(abi.encodePacked(proofElement, computedHash));\\n        }\\n        j = j / 2;\\n    }\\n\\n    return computedHash == rootHash;\\n}\\n```\\n\\nThe current implementation will validate the provided “leaf” and return `true`. This is a known problem of Merkle trees https://en.wikipedia.org/wiki/Merkle_tree#Second_preimage_attack.\\nProvide a hash from within the Merkle tree as the `leaf` argument. The index has to match the index of that node in regards to its current level in the tree. The `rootHash` has to be the correct Merkle tree `rootHash`. The proof has to skip the necessary number of levels because the nodes “underneath” the provided “leaf” will not be processed.

Impact:

Recommended mitigation:
A remediation needs a fixed Merkle tree size as well as the addition of a byte prepended to each node in the tree. Another way would be to create a structure for the Merkle node and mark it as `leaf` or no `leaf`.\\nCorresponding issue in plasma-contracts repo: https://github.com/omisego/plasma-contracts/issues/425
Vulnerability: EthVault - Unused state variable
Severity: low

Description:
The state variable `withdrawEntryCounter` is not used in the code.\\n```\\nuint256 private withdrawEntryCounter = 0;\\n```\\n

Impact:

Recommended mitigation:
Remove it from the contract.
Vulnerability: ECDSA error value is not handled
Severity: low

Description:
Resolution\\nThis was addressed in commit 32288ccff5b867a7477b4eaf3beb0587a4684d7a by adding a check that the returned value is nonzero.\\nThe OpenZeppelin `ECDSA` library returns `address(0x00)` for many cases with malformed signatures:\\n```\\nif (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {\\n    return address(0);\\n}\\n\\nif (v != 27 && v != 28) {\\n    return address(0);\\n}\\n```\\n\\nThe `PaymentOutputToPaymentTxCondition` contract does not explicitly handle this case:\\n```\\naddress payable owner = inputTx.outputs[outputIndex].owner();\\nrequire(owner == ECDSA.recover(eip712.hashTx(spendingTx), signature), "Tx in not signed correctly");\\n\\nreturn true;\\n```\\n

Impact:

Recommended mitigation:
Adding a check to handle this case will make it easier to reason about the code.\\nCorresponding issue in plasma-contracts repo: https://github.com/omisego/plasma-contracts/issues/454
Vulnerability: No existence checks on framework block and timestamp reads
Severity: low

Description:
The exit game libraries make several queries to the main `PlasmaFramework` contract where plasma block hashes and timestamps are stored. In multiple locations, the return values of these queries are not checked for existence.\\nPaymentStartStandardExit.setupStartStandardExitData:\\n```\\n(, uint256 blockTimestamp) = controller.framework.blocks(utxoPos.blockNum());\\n```\\n\\nPaymentChallengeIFENotCanonical.respond:\\n```\\n(bytes32 root, ) = self.framework.blocks(utxoPos.blockNum());\\n```\\n\\nPaymentPiggybackInFlightExit.enqueue:\\n```\\n(, uint256 blockTimestamp) = controller.framework.blocks(utxoPos.blockNum());\\n```\\n\\nTxFinalizationVerifier.checkInclusionProof:\\n```\\n(bytes32 root,) = data.framework.blocks(data.txPos.blockNum());\\n```\\n

Impact:

Recommended mitigation:
Although none of these examples seem exploitable, adding existence checks makes it easier to reason about the code. Each query to `PlasmaFramework.blocks` should be followed with a check that the returned value is nonzero.\\nCorresponding issue in plasma-contracts repo: https://github.com/omisego/plasma-contracts/issues/463
Vulnerability: BondSize - effectiveUpdateTime should be uint64
Severity: low

Description:
In BondSize, the mechanism to update the size of the bond has a grace period after which the new bond size becomes active.\\nWhen updating the bond size, the time is casted as a `uint64` and saved in a `uint128` variable.\\n```\\nuint128 effectiveUpdateTime;\\n```\\n\\n```\\nuint64 constant public WAITING\\_PERIOD = 2 days;\\n```\\n\\n```\\nself.effectiveUpdateTime = uint64(now) + WAITING\\_PERIOD;\\n```\\n\\nThere's no need to use a `uint128` to save the time if it never will take up that much space.

Impact:

Recommended mitigation:
Change the type of the `effectiveUpdateTime` to `uint64`.\\n```\\n- uint128 effectiveUpdateTime;\\n+ uint64 effectiveUpdateTime;\\n```\\n
Vulnerability: PaymentExitGame contains several redundant plasmaFramework declarations
Severity: low

Description:
`PaymentExitGame` inherits from both `PaymentInFlightExitRouter` and `PaymentStandardExitRouter`. All three contracts declare and initialize their own `PlasmaFramework` variable. This pattern can be misleading, and may lead to subtle issues in future versions of the code.\\n`PaymentExitGame` declaration:\\n```\\nPlasmaFramework private plasmaFramework;\\n```\\n\\n`PaymentInFlightExitRouter` declaration:\\n```\\nPlasmaFramework private framework;\\n```\\n\\n`PaymentStandardExitRouter` declaration:\\n```\\nPlasmaFramework private framework;\\n```\\n\\nEach variable is initialized in the corresponding file's constructor.

Impact:

Recommended mitigation:
Introduce an inherited contract common to `PaymentStandardExitRouter` and `PaymentInFlightExitRouter` with the `PlasmaFramework` variable. Make the variable internal so it is visible to inheriting contracts.
Vulnerability: Creating proposal is not trustless in Pull Pattern
Severity: high

Description:
Usually, if someone submits a proposal and transfers some amount of tribute tokens, these tokens are transferred back if the proposal is rejected. But if the proposal is not processed before the emergency processing, these tokens will not be transferred back to the proposer. This might happen if a tribute token or a deposit token transfers are blocked.\\n```\\nif (!emergencyProcessing) {\\n    require(\\n        proposal.tributeToken.transfer(proposal.proposer, proposal.tributeOffered),\\n        "failing vote token transfer failed"\\n    );\\n```\\n\\nTokens are not completely lost in that case, they now belong to the LAO shareholders and they might try to return that money back. But that requires a lot of coordination and time and everyone who ragequits during that time will take a part of that tokens with them.

Impact:

Recommended mitigation:
Resolution\\nthis issue no longer exists in the Pull Pattern update, due to the fact that emergency processing and in function ERC20 transfers are removed.\\nPull pattern for token transfers would solve the issue.
Vulnerability: Emergency processing can be blocked in Pull Pattern
Severity: high

Description:
The main reason for the emergency processing mechanism is that there is a chance that some token transfers might be blocked. For example, a sender or a receiver is in the USDC blacklist. Emergency processing saves from this problem by not transferring tribute token back to the user (if there is some) and rejecting the proposal.\\n```\\nif (!emergencyProcessing) {\\n    require(\\n        proposal.tributeToken.transfer(proposal.proposer, proposal.tributeOffered),\\n        "failing vote token transfer failed"\\n    );\\n```\\n\\nThe problem is that there is still a deposit transfer back to the sponsor and it could be potentially blocked too. If that happens, proposal can't be processed and the LAO is blocked.

Impact:

Recommended mitigation:
Implementing pull pattern for all token withdrawals would solve the problem. The alternative solution would be to also keep the deposit tokens in the LAO, but that makes sponsoring the proposal more risky for the sponsor.
Vulnerability: Token Overflow might result in system halt or loss of funds
Severity: high

Description:
If a token overflows, some functionality such as `processProposal`, `cancelProposal` will break due to safeMath reverts. The overflow could happen because the supply of the token was artificially inflated to oblivion.\\nThis issue was pointed out by Heiko Fisch in Telegram chat.\\nAny function using `internalTransfer()` can result in an overflow:\\n```\\nfunction max(uint256 x, uint256 y) internal pure returns (uint256) {\\n    return x >= y ? x : y;\\n}\\n```\\n

Impact:

Recommended mitigation:
We recommend to allow overflow for broken or malicious tokens. This is to prevent system halt or loss of funds. It should be noted that in case an overflow occurs, the balance of the token will be incorrect for all token holders in the system.\\n`rageKick`, `rageQuit` were fixed by not using safeMath within the function code, however this fix is risky and not recommended, as there are other overflows in other functions that might still result in system halt or loss of funds.\\nOne suggestion is having a function named `unsafeInternalTransfer()` which does not use safeMath for the cases that overflow should be allowed. This mainly adds better readability to the code.\\nIt is still a risky fix and a better solution should be planned.
Vulnerability: Whitelisted tokens limit
Severity: high

Description:
`_ragequit` function is iterating over all whitelisted tokens:\\n```\\nfor (uint256 i = 0; i < tokens.length; i++) {\\n    uint256 amountToRagequit = fairShare(userTokenBalances[GUILD][tokens[i]], sharesAndLootToBurn, initialTotalSharesAndLoot);\\n    // deliberately not using safemath here to keep overflows from preventing the function execution (which would break ragekicks)\\n    // if a token overflows, it is because the supply was artificially inflated to oblivion, so we probably don't care about it anyways\\n    userTokenBalances[GUILD][tokens[i]] -= amountToRagequit;\\n    userTokenBalances[memberAddress][tokens[i]] += amountToRagequit;\\n}\\n```\\n\\nIf the number of tokens is too big, a transaction can run out of gas and all funds will be blocked forever. Ballpark estimation of this number is around 300 tokens based on the current OpCode gas costs and the block gas limit.

Impact:

Recommended mitigation:
A simple solution would be just limiting the number of whitelisted tokens.\\nIf the intention is to invest in many new tokens over time, and it's not an option to limit the number of whitelisted tokens, it's possible to add a function that removes tokens from the whitelist. For example, it's possible to add a new type of proposals, that is used to vote on token removal if the balance of this token is zero. Before voting for that, shareholders should sell all the balance of that token.
Vulnerability: Whitelist proposal duplicate  Won't Fix
Severity: low

Description:
Every time when a whitelist proposal is sponsored, it's checked that there is no other sponsored whitelist proposal with the same token. This is done in order to avoid proposal duplicates.\\n```\\n// whitelist proposal\\nif (proposal.flags[4]) {\\n    require(!tokenWhitelist[address(proposal.tributeToken)], "cannot already have whitelisted the token");\\n    require(!proposedToWhitelist[address(proposal.tributeToken)], 'already proposed to whitelist');\\n    proposedToWhitelist[address(proposal.tributeToken)] = true;\\n```\\n\\nThe issue is that even though you can't sponsor a duplicate proposal, you can still submit a new proposal with the same token.

Impact:

Recommended mitigation:
Check that there is currently no sponsored proposal with the same token on proposal submission.
Vulnerability: Moloch - bool[6] flags can be changed to a dedicated structure  Won't Fix
Severity: low

Description:
The Moloch contract uses a structure that includes an array of bools to store a few flags about the proposal:\\n```\\nbool[6] flags; // [sponsored, processed, didPass, cancelled, whitelist, guildkick]\\n```\\n\\nThis makes reasoning about the correctness of the code a bit complicated because one needs to remember what each item in the flag list stands for. The make the reader's life simpler a dedicated structure can be created that incorporates all of the required flags.\\n```\\n        bool[6] memory flags; // [sponsored, processed, didPass, cancelled, whitelist, guildkick]\\n```\\n

Impact:

Recommended mitigation:
Based on the provided examples change the `bool[6] flags` to the proposed examples.\\nFlags as bool array with enum (proposed)\\nThis second contract implements the `flags` as a defined structure with each named element representing a specific flag. This method makes clear which flag is accessed because they are referred to by the name, not by the index.\\nThis third contract has the least amount of changes to the code and uses an enum structure to handle the index.\\n```\\npragma solidity 0.5.15;\\n\\ncontract FlagsEnum {\\n    struct Proposal {\\n        address applicant;\\n        uint value;\\n        bool[3] flags; // [sponsored, processed, kicked]\\n    }\\n   \\n    enum ProposalFlags {\\n        SPONSORED,\\n        PROCESSED,\\n        KICKED\\n    }\\n   \\n    uint proposalCount;\\n   \\n    mapping(uint256 => Proposal) public proposals;\\n   \\n    function addProposal(uint \\_value, bool \\_sponsored, bool \\_processed, bool \\_kicked) public returns (uint) {\\n        Proposal memory proposal = Proposal({\\n            applicant: msg.sender,\\n            value: \\_value,\\n            flags: [\\_sponsored, \\_processed, \\_kicked]\\n        });\\n       \\n        proposals[proposalCount] = proposal;\\n        proposalCount += 1;\\n       \\n        return (proposalCount);\\n    }\\n   \\n    function getProposal(uint \\_proposalId) public view returns (address, uint, bool, bool, bool) {\\n        return (\\n            proposals[\\_proposalId].applicant,\\n            proposals[\\_proposalId].value,\\n            proposals[\\_proposalId].flags[uint(ProposalFlags.SPONSORED)],\\n            proposals[\\_proposalId].flags[uint(ProposalFlags.PROCESSED)],\\n            proposals[\\_proposalId].flags[uint(ProposalFlags.KICKED)]\\n        );\\n    }\\n}\\n```\\n
Vulnerability: Passing duplicate tokens to Redemptions and TokenRequest may have unintended consequences
Severity: medium

Description:
Both `Redemptions` and `TokenRequest` are initialized with a list of acceptable tokens to use with each app. For `Redemptions`, the list of tokens corresponds to an organization's treasury assets. For `TokenRequest`, the list of tokens corresponds to tokens accepted for payment to join an organization. Neither contract makes a uniqueness check on input tokens during initialization, which can lead to unintended behavior.\\nIn `Redemptions`, each of an organization's assets are redeemed according to the sender's proportional ownership in the org. The redemption process iterates over the `redeemableTokens` list, paying out the sender their proportion of each token listed:\\n```\\nfor (uint256 i = 0; i < redeemableTokens.length; i++) {\\n    vaultTokenBalance = vault.balance(redeemableTokens[i]);\\n\\n    redemptionAmount = \\_burnableAmount.mul(vaultTokenBalance).div(burnableTokenTotalSupply);\\n    totalRedemptionAmount = totalRedemptionAmount.add(redemptionAmount);\\n\\n    if (redemptionAmount > 0) {\\n        vault.transfer(redeemableTokens[i], msg.sender, redemptionAmount);\\n    }\\n}\\n```\\n\\nIf a token address is included more than once, the sender will be paid out more than once, potentially earning many times more than their proportional share of the token.\\nIn `TokenRequest`, this behavior does not allow for any significant deviation from expected behavior. It was included because the initialization process is similar to that of `Redemptions`.

Impact:

Recommended mitigation:
Resolution\\nThis was addressed in Redemptions commit 2b0034206a5b9cdf239da7a51900e89d9931554f by checking `redeemableTokenAdded[token] == false` for each subsequent token added during initialization. Note that ordering is not enforced.\\nAdditionally, the issue in `TokenRequest` was addressed in commit eb4181961093439f142f2e74eb706b7f501eb5c0 by requiring that each subsequent token added during initialization has a value strictly greater than the previous token added.\\nDuring initialization in both apps, check that input token addresses are unique. One simple method is to require that token addresses are submitted in ascending order, and that each subsequent address added is greater than the one before.
Vulnerability: The Delay app allows scripts to be paused even after execution time has elapsed
Severity: medium

Description:
The `Delay` app is used to configure a delay between when an evm script is created and when it is executed. The entry point for this process is `Delay.delayExecution`, which stores the input script with a future execution date:\\n```\\nfunction \\_delayExecution(bytes \\_evmCallScript) internal returns (uint256) {\\n    uint256 delayedScriptIndex = delayedScriptsNewIndex;\\n    delayedScriptsNewIndex++;\\n\\n    delayedScripts[delayedScriptIndex] = DelayedScript(getTimestamp64().add(executionDelay), 0, \\_evmCallScript);\\n\\n    emit DelayedScriptStored(delayedScriptIndex);\\n\\n    return delayedScriptIndex;\\n}\\n```\\n\\nAn auxiliary capability of the `Delay` app is the ability to “pause” the delayed script, which sets the script's `pausedAt` value to the current block timestamp:\\n```\\nfunction pauseExecution(uint256 \\_delayedScriptId) external auth(PAUSE\\_EXECUTION\\_ROLE) {\\n    require(!\\_isExecutionPaused(\\_delayedScriptId), ERROR\\_CAN\\_NOT\\_PAUSE);\\n    delayedScripts[\\_delayedScriptId].pausedAt = getTimestamp64();\\n\\n    emit ExecutionPaused(\\_delayedScriptId);\\n}\\n```\\n\\nA paused script cannot be executed until `resumeExecution` is called, which extends the script's `executionTime` by the amount of time paused. Essentially, the delay itself is paused:\\n```\\nfunction resumeExecution(uint256 \\_delayedScriptId) external auth(RESUME\\_EXECUTION\\_ROLE) {\\n    require(\\_isExecutionPaused(\\_delayedScriptId), ERROR\\_CAN\\_NOT\\_RESUME);\\n    DelayedScript storage delayedScript = delayedScripts[\\_delayedScriptId];\\n\\n    uint64 timePaused = getTimestamp64().sub(delayedScript.pausedAt);\\n    delayedScript.executionTime = delayedScript.executionTime.add(timePaused);\\n    delayedScript.pausedAt = 0;\\n\\n    emit ExecutionResumed(\\_delayedScriptId);\\n}\\n```\\n\\nA delayed script whose execution time has passed and is not currently paused should be able to be executed via the `execute` function. However, the `pauseExecution` function still allows the aforementioned script to be paused, halting execution.

Impact:

Recommended mitigation:
Add a check to `pauseExecution` to ensure that execution is not paused if the script's execution delay has already transpired.
Vulnerability: Delay.execute can re-enter and re-execute the same script twice
Severity: low

Description:
`Delay.execute` does not follow the “checks-effects-interactions” pattern, and deletes a delayed script only after the script is run. Because the script being run executes arbitrary external calls, a script can be created that re-enters `Delay` and executes itself multiple times before being deleted:\\n```\\n/\\*\\*\\n\\* @notice Execute the script with ID `\\_delayedScriptId`\\n\\* @param \\_delayedScriptId The ID of the script to execute\\n\\*/\\nfunction execute(uint256 \\_delayedScriptId) external {\\n    require(canExecute(\\_delayedScriptId), ERROR\\_CAN\\_NOT\\_EXECUTE);\\n    runScript(delayedScripts[\\_delayedScriptId].evmCallScript, new bytes(0), new address[](0));\\n\\n    delete delayedScripts[\\_delayedScriptId];\\n\\n    emit ExecutedScript(\\_delayedScriptId);\\n}\\n```\\n

Impact:

Recommended mitigation:
Add the `Delay` contract address to the `runScript` blacklist, or delete the delayed script from storage before it is run.
Vulnerability: Delay.cancelExecution should revert on a non-existent script id
Severity: low

Description:
`cancelExecution` makes no existence check on the passed-in script ID, clearing its storage slot and emitting an event:\\n```\\n/\\*\\*\\n\\* @notice Cancel script execution with ID `\\_delayedScriptId`\\n\\* @param \\_delayedScriptId The ID of the script execution to cancel\\n\\*/\\nfunction cancelExecution(uint256 \\_delayedScriptId) external auth(CANCEL\\_EXECUTION\\_ROLE) {\\n    delete delayedScripts[\\_delayedScriptId];\\n\\n    emit ExecutionCancelled(\\_delayedScriptId);\\n}\\n```\\n

Impact:

Recommended mitigation:
Add a check that the passed-in script exists.