DYAD - Evo'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: 18/183

Findings: 5

Award: $501.93

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

Labels

bug
3 (High Risk)
satisfactory
sufficient quality report
edited-by-warden
:robot:_09_group
duplicate-930

Awards

238.0297 USDC - $238.03

External Links

Lines of code

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

Vulnerability details

Impact

withdraw method can be blocked permanently for all ids for each block.

Proof of Concept

depsoit amount for a note id by design can't be withdrawn immediately, The user should wait for the next block to be able to withdraw his amount, Ethereum generate new block every 12 seconds, meaning the user who make a deposit he should wait at least a 12 seconds to be able to withdraw, which is on purpose as the protocol made this protection against flash loan attacks or any deposit and withdraw in one time transaction.

However, because of this condition idToBlockOfLastDeposit[id] = block.number, it can cause DoS and block the withdraw method, a simple scenario that Bob can call deposit method and pass any note id with 1 WEI of depsoit amount to any Vault:

A simple scenario:

It seems a short time to wait, and Alex wasn't blocked for long time. However, this unfortunately could not be the case, Bob could use this bug to achieve a full block for many ids for many consecutive blocks.

The critical scenario:

  • Bob will create a vault contract (BVault).
  • Bob will create a contract with a method to call deposit with 1 WEI amount and pass his vault address within a loop of all note ids.
for (uint i = 0; i < Ids; i++) { VaultManagerV2.deposit(Ids[i], BVault, 1 WEI); }
  • Calls will be done to his vault since there is no check for licensed vault on deposit method.
  • Withdrawals for all ids will be blocked on withdraw until the next block.
  • Bob will repeat above for each next block.
  • The protocol withdrawals will be blocked for next blocks until Bob stop.

This attack will cost nothing except the TX fee.

Tools Used

Manual Review

  • Remove the condition and use different implementation or keep the condition but allow the deposit only for valid nft owner.

Assessed type

DoS

#0 - c4-pre-sort

2024-04-27T11:23:38Z

JustDravee marked the issue as duplicate of #1103

#1 - c4-pre-sort

2024-04-27T11:51:47Z

JustDravee marked the issue as duplicate of #489

#2 - c4-pre-sort

2024-04-29T09:25:31Z

JustDravee marked the issue as sufficient quality report

#3 - c4-judge

2024-05-05T20:25:21Z

koolexcrypto marked the issue as not a duplicate

#4 - c4-judge

2024-05-05T20:25:32Z

koolexcrypto marked the issue as duplicate of #1266

#5 - c4-judge

2024-05-11T12:19:02Z

koolexcrypto marked the issue as satisfactory

#6 - c4-judge

2024-05-28T19:12:58Z

koolexcrypto marked the issue as duplicate of #930

Awards

3.8221 USDC - $3.82

Labels

bug
3 (High Risk)
satisfactory
sufficient quality report
upgraded by judge
:robot:_28_group
duplicate-830

External Links

Lines of code

https://github.com/code-423n4/2024-04-dyad/blob/4a987e536576139793a1c04690336d06c93fca90/src/core/VaultManagerV2.sol#L148

Vulnerability details

Impact

A revert will be done in withdraw when users try to withdraw from unbounded kerosene's vault, blocking the users from being able to withdraw their tokens.

Proof of Concept

Users will not be able to withdraw unbounded kerosene tokens, _vault.oracle().decimals() is being called in withdraw method but it seems there is no implementation of oracle in Vault.kerosine.unbounded.sol contract, according to the withdraw of unbounded kerosene, the transaction will revert at 10**_vault.oracle().decimals().

Since we can call withdraw for any vault address, if we call the method _vault.oracle().decimals() of deployed Vault.kerosine.unbounded.sol contract, an EVM revert will be done since no implementation exist, an example contract for implemented oracle, check Vault contract IAggregatorV3 public immutable oracle.

It applies on redeemDyad too since redeemDyad method is calling withdraw(id, vault, asset, to).

Tools Used

Manual review

Add oracle variable to Vault.kerosine.unbounded.sol contract.

Assessed type

DoS

#0 - c4-pre-sort

2024-04-26T21:07:11Z

JustDravee marked the issue as duplicate of #1048

#1 - c4-pre-sort

2024-04-28T18:39:30Z

JustDravee marked the issue as duplicate of #830

#2 - c4-pre-sort

2024-04-29T08:44:50Z

JustDravee marked the issue as sufficient quality report

#3 - c4-judge

2024-05-11T20:05:36Z

koolexcrypto marked the issue as satisfactory

#4 - c4-judge

2024-05-13T18:35:55Z

koolexcrypto changed the severity to 3 (High Risk)

Awards

32.4128 USDC - $32.41

Labels

bug
3 (High Risk)
satisfactory
sufficient quality report
upgraded by judge
edited-by-warden
:robot:_28_group
duplicate-397

External Links

Lines of code

https://github.com/code-423n4/2024-04-dyad/blob/4a987e536576139793a1c04690336d06c93fca90/src/core/VaultManagerV2.sol#L250

Vulnerability details

Impact

Users will not be able to withdraw kerosene tokens from unbounded kerosine vault incase his none kerosene value less than his kerosine amount.

Proof of Concept

Users can't withdraw kerosene tokens from Vault.kerosine.unbounded, withdraw method will check if (getNonKeroseneValue(id) - value < dyadMinted) otherwise revert, incase of unbounded koresene vault, the user will not be able to withdraw his kerosene tokens if he has no value of non-koresene collateral, which must not be a pre-condition for koresene.

Break down: Since the user didn't mint dyad, he should be able to withdraw koresene tokens, but according to the condition getNonKeroseneValue(id) - value < dyadMinted, getNonKeroseneValue will get the none kerosene value (eth,weth..), but the user might have zero value of it. so he will be blocked from withdrawing kerosene tokens.

Another case: A liquidator liquidated a user, since the user being liquidated he has less collateral value or none, but he still has kerosene tokens that he wants to withdraw, but he couldn't since his collateral value is less than his kerosene tokens in unbounded kerosene vault or has zero of it since a liquation was done and no remaining.

Note that getNonKeroseneValue is returning totalUsdValue for all note id's vaults, as the value is USD for note id collaterals, which will impact (getNonKeroseneValue(id) - value < dyadMinted condition.

Tools Used

Manual Review

Exclude Kerosene unbounded vault from (getNonKeroseneValue(id) - value < dyadMinted condition.

Assessed type

DoS

#0 - c4-pre-sort

2024-04-26T21:09:50Z

JustDravee marked the issue as duplicate of #397

#1 - c4-pre-sort

2024-04-29T08:48:18Z

JustDravee marked the issue as sufficient quality report

#2 - c4-judge

2024-05-11T19:23:12Z

koolexcrypto marked the issue as satisfactory

#3 - c4-judge

2024-05-13T18:33:04Z

koolexcrypto changed the severity to 3 (High Risk)

Findings Information

🌟 Selected for report: Pataroff

Also found by: Egis_Security, Evo, Jorgect, MrPotatoMagic, SBSecurity, T1MOH, carrotsmuggler, ljj

Labels

bug
2 (Med Risk)
satisfactory
sufficient quality report
:robot:_06_group
duplicate-100

Awards

223.9474 USDC - $223.95

External Links

Lines of code

https://github.com/code-423n4/2024-04-dyad/blob/4a987e536576139793a1c04690336d06c93fca90/src/core/Dyad.sol#L46

Vulnerability details

Impact

burnDyad could cause DoS for other users transactions when they attempt to burn their full amount of dyad.

Proof of Concept

burnDyad is allowing the user to burn dyad amounts for his note id and other users note ids, It seems a part of the protocol design that allow such a feature to make burn dyad availabe not only for self burn amount of mintedDyad, also for others.

After investigating the method, we can see that dyad.burn(id, msg.sender, amount) is being called from VaultManagerV2 address as the caller (msg.sender), now if we move further to burn method, we will find that _burn(from, amount) is burning Dyad ERC20 tokens from the user caller address, moving forward in the next line mintedDyad[msg.sender][id] -= amount it seems that an amount is being decreased from mintedDyad mapping for the passed note id.

The case of the issue: Supposed Bob would like to burn a 100 Dyad (his max Dyad minted amount) to achieve a withdraw for his collateral, Bob will call burn passing 100e18 amount as 100 of Dyad tokens, Alex will front-run Bob and call burn method, passing the note id of Bob (let's say id 8) with a minimum amount of 1 WEI Dyad , Bob's transaction will fail since his amount of mintedDyad become less than 100e18 and it will revert here mintedDyad[msg.sender][id] -= amount.

Since no check for isDNftOwner modifier on burn method, anyone can pass different note ids for other users and decrease their mintedDyad amount, this attack is cheap.

Tools Used

Manual Review

Add isDNftOwner modifier on burn method, update other parts of the code accordingly.

Assessed type

DoS

#0 - c4-pre-sort

2024-04-27T13:13:26Z

JustDravee marked the issue as duplicate of #409

#1 - c4-pre-sort

2024-04-29T09:36:17Z

JustDravee marked the issue as sufficient quality report

#2 - c4-judge

2024-05-05T12:01:29Z

koolexcrypto marked the issue as unsatisfactory: Invalid

#3 - c4-judge

2024-05-09T11:27:57Z

koolexcrypto marked the issue as not a duplicate

#4 - c4-judge

2024-05-09T11:28:07Z

koolexcrypto marked the issue as duplicate of #74

#5 - c4-judge

2024-05-09T11:28:18Z

koolexcrypto marked the issue as nullified

#6 - c4-judge

2024-05-09T11:28:22Z

koolexcrypto marked the issue as not nullified

#7 - c4-judge

2024-05-10T10:14:49Z

koolexcrypto marked the issue as duplicate of #992

#8 - c4-judge

2024-05-11T12:15:51Z

koolexcrypto marked the issue as satisfactory

#9 - c4-judge

2024-05-28T10:29:44Z

koolexcrypto marked the issue as duplicate of #100

Awards

3.7207 USDC - $3.72

Labels

bug
2 (Med Risk)
satisfactory
sufficient quality report
:robot:_08_group
duplicate-70

External Links

Lines of code

https://github.com/code-423n4/2024-04-dyad/blob/4a987e536576139793a1c04690336d06c93fca90/src/core/KerosineManager.sol#L44

Vulnerability details

Impact

incorrect implementation of isLicensed method in Kerosine Manager.

Proof of Concept

Wrong implementation in KerosineManager.sol contract, isLicensed should call mapping (address => bool) public isLicensed to check if vault isLicensed true or false.

While return vaults.contains(vault) is checking if the vault exist in the vaults of EnumerableSet.AddressSet variable. In this case it's unable to make a vault in KerosineManager not Licensed, meaning the vault need to be removed to achieve not Licensed value.

isLicensed will return false;

Tools Used

Manual Review

Change isLicensed method in KerosineManager to be like Licenser contract, or use isLicensed in Licenser contract.

Assessed type

Other

#0 - c4-pre-sort

2024-04-27T16:56:34Z

JustDravee marked the issue as duplicate of #70

#1 - c4-pre-sort

2024-04-29T09:37:05Z

JustDravee marked the issue as sufficient quality report

#2 - c4-judge

2024-05-11T20:01:09Z

koolexcrypto marked the issue as satisfactory

#3 - c4-judge

2024-05-12T10:40:22Z

koolexcrypto marked the issue as not a duplicate

#4 - c4-judge

2024-05-12T10:42:18Z

koolexcrypto marked the issue as duplicate of #70

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