DYAD - turvy_fuzz's results

The first capital efficient overcollateralized stablecoin.

General Information

Platform: Code4rena

Start Date: 18/04/2024

Pot Size: $36,500 USDC

Total HM: 19

Participants: 183

Period: 7 days

Judge: Koolex

Id: 367

League: ETH

DYAD

Findings Distribution

Researcher Performance

Rank: 117/183

Findings: 2

Award: $7.37

🌟 Selected for report: 0

🚀 Solo Findings: 0

Lines of code

https://github.com/code-423n4/2024-04-dyad/blob/main/src/core/VaultManagerV2.sol#L127 https://github.com/code-423n4/2024-04-dyad/blob/main/src/core/VaultManagerV2.sol#L143

Vulnerability details

Impact

Attacker can prevent owners from withdrawing without actually depositing any amount since vault address isn't validated and can be any address including the attacker own custom vault contract. Therefore at zero cost.

Proof of Concept

The withdraw() function implements a mechanism to prevent flashloan attack issue by the Id last deposited when withdrawing:

  function withdraw(
    uint    id,
    address vault,
    uint    amount,
    address to
  ) 
    public
      isDNftOwner(id)
  {
@>  if (idToBlockOfLastDeposit[id] == block.number) revert DepositedInSameBlock();
    uint dyadMinted = dyad.mintedDyad(address(this), id);
    Vault _vault = Vault(vault);
    uint value = amount * _vault.assetPrice() 
                  * 1e18 
                  / 10**_vault.oracle().decimals() 
                  / 10**_vault.asset().decimals();
    if (getNonKeroseneValue(id) - value < dyadMinted) revert NotEnoughExoCollat();
    _vault.withdraw(id, to, amount);
    if (collatRatio(id) < MIN_COLLATERIZATION_RATIO)  revert CrTooLow(); 
  }

This last deposit mapping is updated on the deposit function:

 function deposit(
    uint    id,
    address vault,
    uint    amount
  ) 
    external 
      isValidDNft(id)
  {
    idToBlockOfLastDeposit[id] = block.number;
    Vault _vault = Vault(vault);
    _vault.asset().safeTransferFrom(msg.sender, address(vault), amount);
    _vault.deposit(id, amount);
  }

Notice from the above function shown, there where no access control or permission required to deposited for any valid Id, also notice there are no license check for the vault to be deposited. This means an attacker can prevent owners from withdrawing without actually depositing any amount since vault address isn't validated and can be any address including the attacker own custom vault contract, and since there are no permission needed, can frontrun whenever attempts to withdraw and update the lastdeposited to the same block.number as the withdraw transaction.

Tools Used

Manual review

Implement an access control mechanism to allow only addresses with the owner's permission/allowance.

Assessed type

Access Control

#0 - c4-pre-sort

2024-04-27T11:35:03Z

JustDravee marked the issue as duplicate of #1103

#1 - c4-pre-sort

2024-04-27T11:45:57Z

JustDravee marked the issue as duplicate of #489

#2 - c4-pre-sort

2024-04-29T09:31:34Z

JustDravee marked the issue as sufficient quality report

#3 - c4-judge

2024-05-05T20:38:08Z

koolexcrypto marked the issue as unsatisfactory: Invalid

#4 - c4-judge

2024-05-05T21:11:32Z

koolexcrypto marked the issue as nullified

#5 - c4-judge

2024-05-05T21:11:41Z

koolexcrypto marked the issue as not nullified

#6 - c4-judge

2024-05-08T15:29:28Z

koolexcrypto marked the issue as duplicate of #1001

#7 - c4-judge

2024-05-11T19:44:50Z

koolexcrypto marked the issue as satisfactory

Awards

7.3512 USDC - $7.35

Labels

bug
2 (Med Risk)
downgraded by judge
satisfactory
sufficient quality report
:robot:_39_group
duplicate-118

External Links

Lines of code

https://github.com/code-423n4/2024-04-dyad/blob/main/src/core/VaultManagerV2.sol#L101 https://github.com/code-423n4/2024-04-dyad/blob/main/src/core/VaultManagerV2.sol#L113

Vulnerability details

Impact

Attackers can prevent DNftOwners from removing vaults from their Id.

Proof of Concept

Here are the remove functions:

 function remove(
      uint    id,
      address vault
  ) 
    external
      isDNftOwner(id)
  {
@>  if (Vault(vault).id2asset(id) > 0) revert VaultHasAssets();
    if (!vaults[id].remove(vault))     revert VaultNotAdded();
    emit Removed(id, vault);
  }
  function removeKerosene(
      uint    id,
      address vault
  ) 
    external
      isDNftOwner(id)
  {
@>  if (Vault(vault).id2asset(id) > 0)     revert VaultHasAssets();
    if (!vaultsKerosene[id].remove(vault)) revert VaultNotAdded();
    emit Removed(id, vault);
  }

Notice they both check if the vault still has assets in them before allowing them to be removed. These assets can added to the vault through the deposit function with any amount even as little as 1 unit of the token:

function deposit(
    uint    id,
    address vault,
    uint    amount
  ) 
    external 
      isValidDNft(id)
  {
    idToBlockOfLastDeposit[id] = block.number;
    Vault _vault = Vault(vault);
    _vault.asset().safeTransferFrom(msg.sender, address(vault), amount);
@>  _vault.deposit(id, amount);
  }

The issue here is that as we can see, the deposit function has no access control meaning anyone can add access to the vault including when an owner attempts to remove the vault after withdrawing, frontrunning the transition and depositing an insignificant amount to prevent the owner from removing vaults.

Tools Used

Manual Review

Either consider allowing owners to choose to remove vault even if assets are in them, they can still be added back or implement an access control or permission allowance from the Id owners to deposit for them.

Assessed type

DoS

#0 - c4-pre-sort

2024-04-29T07:44:38Z

JustDravee marked the issue as duplicate of #489

#1 - c4-pre-sort

2024-04-29T09:31:34Z

JustDravee marked the issue as sufficient quality report

#2 - c4-judge

2024-05-05T20:33:23Z

koolexcrypto marked the issue as not a duplicate

#3 - c4-judge

2024-05-06T11:31:21Z

koolexcrypto marked the issue as duplicate of #118

#4 - c4-judge

2024-05-11T12:24:22Z

koolexcrypto marked the issue as satisfactory

#5 - c4-judge

2024-05-13T18:37:20Z

koolexcrypto changed the severity to 2 (Med Risk)

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter