msc-smart-contract-auditing/vulnerable-functions-base huggingface dataset:
Vulnerability: zDAO-Token - Revoking vesting tokens right before cliff period expiration might be delayed/front-runned
Severity: low

Description:
The owner of `TokenVesting` contract has the right to revoke the vesting of tokens for any `beneficiary`. By doing so, the amount of tokens that are already vested and weren't released yet are being transferred to the `beneficiary`, and the rest are being transferred to the owner. The `beneficiary` is expected to receive zero tokens in case the revocation transaction was executed before the cliff period is over. Although unlikely, the `beneficiary` may front run this revocation transaction by delaying the revocation (and) or inserting a release transaction right before that, thus withdrawing the vested amount.\\n```\\nfunction release(address beneficiary) public {\\n  uint256 unreleased = getReleasableAmount(beneficiary);\\n  require(unreleased > 0, "Nothing to release");\\n\\n  TokenAward storage award = getTokenAwardStorage(beneficiary);\\n  award.released += unreleased;\\n\\n  targetToken.safeTransfer(beneficiary, unreleased);\\n\\n  emit Released(beneficiary, unreleased);\\n}\\n\\n/\\*\\*\\n \\* @notice Allows the owner to revoke the vesting. Tokens already vested\\n \\* are transfered to the beneficiary, the rest are returned to the owner.\\n \\* @param beneficiary Who the tokens are being released to\\n \\*/\\nfunction revoke(address beneficiary) public onlyOwner {\\n  TokenAward storage award = getTokenAwardStorage(beneficiary);\\n\\n  require(award.revocable, "Cannot be revoked");\\n  require(!award.revoked, "Already revoked");\\n\\n  // Figure out how many tokens were owed up until revocation\\n  uint256 unreleased = getReleasableAmount(beneficiary);\\n  award.released += unreleased;\\n\\n  uint256 refund = award.amount - award.released;\\n\\n  // Mark award as revoked\\n  award.revoked = true;\\n  award.amount = award.released;\\n\\n  // Transfer owed vested tokens to beneficiary\\n  targetToken.safeTransfer(beneficiary, unreleased);\\n  // Transfer unvested tokens to owner (revoked amount)\\n  targetToken.safeTransfer(owner(), refund);\\n\\n  emit Released(beneficiary, unreleased);\\n  emit Revoked(beneficiary, refund);\\n}\\n```\\n

Impact:

Recommended mitigation:
The issue described above is possible, but very unlikely. However, the `TokenVesting` owner should be aware of that, and make sure not to revoke vested tokens closely to cliff period ending.
Vulnerability: zDAO-Token - Vested tokens revocation depends on claiming state
Severity: low

Description:
The owner of the `TokenVesting` contract can revoke the vesting of tokens for any beneficiary by calling `TokenVesting.revoke` only for tokens that have already been claimed using `MerkleTokenVesting.claimAward`. Although anyone can call `MerkleTokenVesting.claimAward` for a given beneficiary, in practice it is mostly the beneficiary's responsibility. This design decision, however, incentivizes the beneficiary to delay the call to `MerkleTokenVesting.claimAward` up to the point when he wishes to cash out, to avoid potential revocation. To revoke vesting tokens the owner will have to claim the award on the beneficiary's behalf first (which might be a gas burden), then call `TokenVesting.revoke`.\\n```\\nfunction revoke(address beneficiary) public onlyOwner {\\n  TokenAward storage award = getTokenAwardStorage(beneficiary);\\n\\n  require(award.revocable, "Cannot be revoked");\\n  require(!award.revoked, "Already revoked");\\n\\n  // Figure out how many tokens were owed up until revocation\\n  uint256 unreleased = getReleasableAmount(beneficiary);\\n  award.released += unreleased;\\n\\n  uint256 refund = award.amount - award.released;\\n\\n  // Mark award as revoked\\n  award.revoked = true;\\n  award.amount = award.released;\\n\\n  // Transfer owed vested tokens to beneficiary\\n  targetToken.safeTransfer(beneficiary, unreleased);\\n  // Transfer unvested tokens to owner (revoked amount)\\n  targetToken.safeTransfer(owner(), refund);\\n\\n  emit Released(beneficiary, unreleased);\\n  emit Revoked(beneficiary, refund);\\n}\\n```\\n

Impact:

Recommended mitigation:
Make sure that the potential owner of a `TokenVesting` contract is aware of this potential issue, and has the required processes in place to handle it.
Vulnerability: zNS - Domain bid might be approved by non owner account
Severity: high

Description:
The spec allows anyone to place a bid for a domain, while only parent domain owners are allowed to approve a bid. Bid placement is actually enforced and purely informational. In practice, `approveDomainBid` allows any parent domain owner to approve bids (signatures) for any other domain even if they do not own it. Once approved, anyone can call `fulfillDomainBid` to create a domain.\\n```\\nfunction approveDomainBid(\\n    uint256 parentId,\\n    string memory bidIPFSHash,\\n    bytes memory signature\\n) external authorizedOwner(parentId) {\\n  bytes32 hashOfSig = keccak256(abi.encode(signature));\\n  approvedBids[hashOfSig] = true;\\n  emit DomainBidApproved(bidIPFSHash);\\n}\\n```\\n

Impact:

Recommended mitigation:
Resolution\\nAddressed with zer0-os/[email protected] by storing the domain request data on-chain.\\nConsider adding a validation check that allows only the parent domain owner to approve bids on one of its domains. Reconsider the design of the system introducing more on-chain guarantees for bids.
Vulnerability: zNS - Insufficient protection against replay attacks
Severity: high

Description:
There is no dedicated data structure to prevent replay attacks on `StakingController`. `approvedBids` mapping offers only partial mitigation, due to the fact that after a domain bid is fulfilled, the only mechanism in place to prevent a replay attack is the `Registrar` contract that might be replaced in the case where `StakingController` is being re-deployed with a different `Registrar` instance. Additionally, the digital signature used for domain bids does not identify the buyer request uniquely enough. The bidder's signature could be replayed in future similar contracts that are deployed with a different registrar or in a different network.\\n```\\nfunction createBid(\\n  uint256 parentId,\\n  uint256 bidAmount,\\n  string memory bidIPFSHash,\\n  string memory name\\n) public pure returns(bytes32) {\\n  return keccak256(abi.encode(parentId, bidAmount, bidIPFSHash, name));\\n}\\n```\\n

Impact:

Recommended mitigation:
Consider adding a dedicated mapping to store the a unique identifier of a bid, as well as adding `address(this)`, `block.chainId`, `registrar` and `nonce` to the message that is being signed by the bidder.
Vulnerability: zNS - domain name collisions
Severity: high

Description:
Domain registration accepts an empty (zero-length) name. This may allow a malicious entity to register two different NFT's for the same visually indinstinguishable text representation of a domain. Similar to this the domain name is mapped to an NFT via a subgraph that connects parent names to the new subdomain using a domain separation character (dot/slash/…). Someone might be able to register `a.b` to `cats.cool` which might resolve to the same domain as if someone registers `cats.cool.a` and then `cats.cool.a.b`.\\n`0/cats/` = `0xfe`\\n`0/cats/<empty-string/` = `0xfe.keccak("")`\\n```\\nfunction registerDomain(\\n  uint256 parentId,\\n  string memory name,\\n  address domainOwner,\\n  address minter\\n) external override onlyController returns (uint256) {\\n  // Create the child domain under the parent domain\\n  uint256 labelHash = uint256(keccak256(bytes(name)));\\n  address controller = msg.sender;\\n\\n  // Domain parents must exist\\n  require(\\_exists(parentId), "Zer0 Registrar: No parent");\\n\\n  // Calculate the new domain's id and create it\\n  uint256 domainId =\\n    uint256(keccak256(abi.encodePacked(parentId, labelHash)));\\n  \\_createDomain(domainId, domainOwner, minter, controller);\\n\\n  emit DomainCreated(domainId, name, labelHash, parentId, minter, controller);\\n\\n  return domainId;\\n```\\n

Impact:

Recommended mitigation:
Disallow empty subdomain names. Disallow domain separators in names (in the offchain component or smart contract).
Vulnerability: zNS - anyone can front-run fulfillDomainBid to lock the domain setting or set different metadata
Severity: medium

Description:
Anyone observing a call to `fulfillDomainBid` can front-run this call for the original bidder, provide different metadata/royalty amount, or lock the metadata, as these parameters are not part of the bidder's signature. The impact is limited as both metadata, royalty amount, and lock state can be changed by the domain owner after creation.\\n```\\n  function fulfillDomainBid(\\n  uint256 parentId,\\n  uint256 bidAmount,\\n  uint256 royaltyAmount,\\n  string memory bidIPFSHash,\\n  string memory name,\\n  string memory metadata,\\n  bytes memory signature,\\n  bool lockOnCreation,\\n  address recipient\\n) external {\\n  bytes32 recoveredBidHash = createBid(parentId, bidAmount, bidIPFSHash, name);\\n  address recoveredBidder = recover(recoveredBidHash, signature);\\n  require(recipient == recoveredBidder, "ZNS: bid info doesnt match/exist");\\n  bytes32 hashOfSig = keccak256(abi.encode(signature));\\n  require(approvedBids[hashOfSig] == true, "ZNS: has been fullfilled");\\n  infinity.safeTransferFrom(recoveredBidder, controller, bidAmount);\\n  uint256 id = registrar.registerDomain(parentId, name, controller, recoveredBidder);\\n  registrar.setDomainMetadataUri(id, metadata);\\n  registrar.setDomainRoyaltyAmount(id, royaltyAmount);\\n  registrar.transferFrom(controller, recoveredBidder, id);\\n  if (lockOnCreation) {\\n    registrar.lockDomainMetadataForOwner(id);\\n  }\\n```\\n

Impact:

Recommended mitigation:
Consider adding `metadata`, `royaltyAmount`, and `lockOnCreation` to the message signed by the bidder if the parent should have some control over `metadata` and lockstatus and restrict access to this function to `msg.sender==recoveredbidder`.
Vulnerability: zNS- Using a digital signature as a hash preimage
Severity: medium

Description:
Using the encoded signature (r,s,v) or the hash of the signature to prevent replay or track if signatures have been seen/used is not recommended in general, as it may introduce signature malleability issues, as two different signature params (r,s,v) may be producable that validly sign the same data.\\nThe impact for this codebase, however, is limited, due to the fact that openzeppelins `ECDSA` wrapper library is used which checks for malleable `ECDSA` signatures (high s value). We still decided to keep this as a medium issue to raise awareness, that it is bad practice to rely on the hash of signatures instead of the hash of the actual signed data for checks.\\nIn another instance in zAuction, a global random nonce is used to prevent replay attacks. This is suboptimal and instead, the hash of the signed data (including a nonce) should be used.\\n```\\n  function fulfillDomainBid(\\n  uint256 parentId,\\n  uint256 bidAmount,\\n  uint256 royaltyAmount,\\n  string memory bidIPFSHash,\\n  string memory name,\\n  string memory metadata,\\n  bytes memory signature,\\n  bool lockOnCreation,\\n  address recipient\\n) external {\\n  bytes32 recoveredBidHash = createBid(parentId, bidAmount, bidIPFSHash, name);\\n  address recoveredBidder = recover(recoveredBidHash, signature);\\n  require(recipient == recoveredBidder, "ZNS: bid info doesnt match/exist");\\n  bytes32 hashOfSig = keccak256(abi.encode(signature));\\n  require(approvedBids[hashOfSig] == true, "ZNS: has been fullfilled");\\n  infinity.safeTransferFrom(recoveredBidder, controller, bidAmount);\\n  uint256 id = registrar.registerDomain(parentId, name, controller, recoveredBidder);\\n  registrar.setDomainMetadataUri(id, metadata);\\n  registrar.setDomainRoyaltyAmount(id, royaltyAmount);\\n  registrar.transferFrom(controller, recoveredBidder, id);\\n  if (lockOnCreation) {\\n    registrar.lockDomainMetadataForOwner(id);\\n  }\\n  approvedBids[hashOfSig] = false;\\n  emit DomainBidFulfilled(\\n    metadata,\\n    name,\\n    recoveredBidder,\\n    id,\\n    parentId\\n  );\\n}\\n```\\n\\n```\\nfunction acceptBid(bytes memory signature, uint256 rand, address bidder, uint256 bid, address nftaddress, uint256 tokenid) external {\\n    address recoveredbidder = recover(toEthSignedMessageHash(keccak256(abi.encode(rand, address(this), block.chainid, bid, nftaddress, tokenid))), signature);\\n    require(bidder == recoveredbidder, 'zAuction: incorrect bidder');\\n    require(!randUsed[rand], 'Random nonce already used');\\n    randUsed[rand] = true;\\n```\\n

Impact:

Recommended mitigation:
Consider creating the bid identifier by hashing the concatenation of all bid parameters instead. Ensure to add replay protection https://github.com/ConsenSys/zer0-zns-audit-2021-05/issues/19. Always check for the hash of the signed data instead of the hash of the encoded signature to track whether a signature has been seen before.\\nConsider implementing Ethereum typed structured data hashing and signing according to EIP-712.
Vulnerability: zNS - Registrar skips __ERC721Pausable_init()
Severity: low

Description:
The initialization function of registrar skips the chained initializer `__ERC721Pausable_init` to initialize `__ERC721_init("Zer0 Name Service", "ZNS")`. This basically skips the following initialization calls:\\n```\\nabstract contract ERC721PausableUpgradeable is Initializable, ERC721Upgradeable, PausableUpgradeable {\\n    function \\_\\_ERC721Pausable\\_init() internal initializer {\\n        \\_\\_Context\\_init\\_unchained(); \\n        \\_\\_ERC165\\_init\\_unchained();\\n        \\_\\_Pausable\\_init\\_unchained();\\n        \\_\\_ERC721Pausable\\_init\\_unchained();\\n    }\\n```\\n\\n```\\nfunction initialize() public initializer {\\n  \\_\\_Ownable\\_init();\\n  \\_\\_ERC721\\_init("Zer0 Name Service", "ZNS");\\n\\n  // create the root domain\\n  \\_createDomain(0, msg.sender, msg.sender, address(0));\\n}\\n```\\n

Impact:

Recommended mitigation:
consider calling the missing initializers to register the interface for erc165 if needed.
Vulnerability: zNS - Registrar is ERC721PausableUpgradeable but there is no way to actually pause it
Severity: low

Description:
The registrar is ownable and pausable but the functionality to pause the contract is not implemented.\\n```\\ncontract Registrar is\\n  IRegistrar,\\n  OwnableUpgradeable,\\n  ERC721PausableUpgradeable\\n{\\n```\\n

Impact:

Recommended mitigation:
Simplification is key. Remove the pausable functionality if the contract is not meant to be paused or consider implementing an external `pause()` function decorated `onlyOwner`.
Vulnerability: zNS - Avoid no-ops
Severity: low

Description:
Code paths that are causing transactions to be ended with an ineffective outcome or no-operation (no actual state changes) are not advisable, as they consume more gas, hide misconfiguration or error cases (e.g. adding the same controller multiple times), and may impact other processes that rely upon transaction's logs.\\nReject adding an already existing controller, and removing non existing controller.\\n```\\n/\\*\\*\\n @notice Authorizes a controller to control the registrar\\n @param controller The address of the controller\\n \\*/\\nfunction addController(address controller) external override onlyOwner {\\n  controllers[controller] = true;\\n  emit ControllerAdded(controller);\\n}\\n\\n/\\*\\*\\n @notice Unauthorizes a controller to control the registrar\\n @param controller The address of the controller\\n \\*/\\nfunction removeController(address controller) external override onlyOwner {\\n  controllers[controller] = false;\\n  emit ControllerRemoved(controller);\\n}\\n```\\n

Impact:

Recommended mitigation:
Consider reverting code paths that end up in ineffective outcomes (i.e. no-operation) as early as possible.
Vulnerability: Simplify claim tokens for a gas discount and less code
Severity: low

Description:
The method `claimTokens` in `TokenDistributor` needs to do a few checks before it can distribute the tokens.\\nA few of these checks can be simplified and optimized.\\nThe method `hashMatch` can be removed because it's only used once and the contents can be moved directly into the parent method.\\n```\\n// can we reproduce the same hash from the raw claim metadata?\\nrequire(hashMatch(user\\_id, user\\_address, user\\_amount, delegate\\_address, leaf, eth\\_signed\\_message\\_hash\\_hex), 'TokenDistributor: Hash Mismatch.');\\n```\\n\\nBecause this method also uses a few other internal calls, they also need to be moved into the parent method.\\n```\\nreturn getDigest(claim) == eth\\_signed\\_message\\_hash\\_hex;\\n```\\n\\n```\\nhashClaim(claim)\\n```\\n\\nMoving the code directly in the parent method and removing them will improve gas costs for users.\\nThe structure `Claim` can also be removed because it's not used anywhere else in the code.

Impact:

Recommended mitigation:
Consider simplifying `claimTokens` and remove unused methods.
Vulnerability: Rename method _hashLeaf to something that represents the validity of the leaf
Severity: low

Description:
The method `_hashLeaf` accepts 3 arguments.\\n```\\nfunction \\_hashLeaf(uint32 user\\_id, uint256 user\\_amount, bytes32 leaf) private returns (bool) {\\n```\\n\\nThe arguments `user_id` and `user_amount` are used to create a keccak256 hash.\\n```\\nbytes32 leaf\\_hash = keccak256(abi.encodePacked(keccak256(abi.encodePacked(user\\_id, user\\_amount))));\\n```\\n\\nThis hash is then checked if it matches the third argument.\\n```\\nreturn leaf == leaf\\_hash;\\n```\\n\\nThe result of the equality is returned by the method.\\nThe name of the method is confusing because it should say that it returns true if the leaf is considered valid.

Impact:

Recommended mitigation:
Resolution\\nClosed because the method was removed in gitcoinco/governance#4\\nConsider renaming the method to something like `isValidLeafHash`.
Vulnerability: Method returns bool but result is never used in TokenDistributor.claimTokens
Severity: low

Description:
The method `_delegateTokens` is called when a user claims their tokens to automatically delegate the claimed tokens to their own address or to a different one.\\n```\\n\\_delegateTokens(user\\_address, delegate\\_address);\\n```\\n\\nThe method accepts the addresses of the delegator and the delegate and returns a boolean.\\n```\\n/\\*\\*\\n\\* @notice execute call on token contract to delegate tokens \\n\\* @return boolean true on success \\n\\*/\\nfunction \\_delegateTokens(address delegator, address delegatee) private returns (bool) {\\n     GTCErc20  GTCToken = GTCErc20(token);\\n     GTCToken.delegateOnDist(delegator, delegatee);\\n     return true; \\n} \\n```\\n\\nBut this boolean is never used.

Impact:

Recommended mitigation:
Remove the returned boolean because it's always returned as `true` anyway and the transaction will be a bit cheaper.
Vulnerability: Improve efficiency by using immutable in TreasuryVester
Severity: low

Description:
The `TreasuryVester` contract when deployed has a few fixed storage variables.\\n```\\ngtc = gtc\\_;\\n```\\n\\n```\\nvestingAmount = vestingAmount\\_;\\nvestingBegin = vestingBegin\\_;\\nvestingCliff = vestingCliff\\_;\\nvestingEnd = vestingEnd\\_;\\n```\\n\\nThese storage variables are defined in the contract.\\n```\\naddress public gtc;\\n```\\n\\n```\\nuint public vestingAmount;\\nuint public vestingBegin;\\nuint public vestingCliff;\\nuint public vestingEnd;\\n```\\n\\nBut they are never changed.

Impact:

Recommended mitigation:
Resolution\\nFixed in gitcoinco/governance#5\\nConsider setting storage variables as `immutable` type for a considerable gas improvement.
Vulnerability: RocketDAOProtocolSettings/RocketDAONodeTrustedSettings - anyone can set/overwrite settings until contract is declared “deployed”  Acknowledged
Severity: high

Description:
The `onlyDAOProtocolProposal` modifier guards all state-changing methods in this contract. However, analog to https://github.com/ConsenSys/rocketpool-audit-2021-03/issues/7, the access control is disabled until the variable `settingsNameSpace.deployed` is set. If this contract is not deployed and configured in one transaction, anyone can update the contract while left unprotected on the blockchain.\\nSee issue 6.5 for a similar issue.\\n```\\nmodifier onlyDAOProtocolProposal() {\\n    // If this contract has been initialised, only allow access from the proposals contract\\n    if(getBool(keccak256(abi.encodePacked(settingNameSpace, "deployed")))) require(getContractAddress('rocketDAOProtocolProposals') == msg.sender, "Only DAO Protocol Proposals contract can update a setting");\\n    \\_;\\n}\\n```\\n\\n```\\nmodifier onlyDAONodeTrustedProposal() {\\n    // If this contract has been initialised, only allow access from the proposals contract\\n    if(getBool(keccak256(abi.encodePacked(settingNameSpace, "deployed")))) require(getContractAddress('rocketDAONodeTrustedProposals') == msg.sender, "Only DAO Node Trusted Proposals contract can update a setting");\\n    \\_;\\n}\\n```\\n\\nThere are at least 9 more occurrences of this pattern.

Impact:

Recommended mitigation:
Restrict access to the methods to a temporary trusted account (e.g. guardian) until the system bootstrapping phase ends by setting `deployed` to `true.`
Vulnerability: RocketStorage - anyone can set/update values before the contract is initialized
Severity: high

Description:
According to the deployment script, the contract is deployed, and settings are configured in multiple transactions. This also means that for a period of time, the contract is left unprotected on the blockchain. Anyone can delete/set any value in the centralized data store. An attacker might monitor the mempool for new deployments of the `RocketStorage` contract and front-run calls to `contract.storage.initialised` setting arbitrary values in the system.\\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

Impact:

Recommended mitigation:
Restrict access to the methods to a temporary trusted account (e.g. guardian) until the system bootstrapping phase ends by setting `initialised` to `true.`