Spectra - ArmedGoose's results

A permissionless interest rate derivatives protocol on Ethereum.

General Information

Platform: Code4rena

Start Date: 23/02/2024

Pot Size: $36,500 USDC

Total HM: 2

Participants: 39

Period: 7 days

Judge: Dravee

Id: 338

League: ETH

Spectra

Findings Distribution

Researcher Performance

Rank: 2/39

Findings: 2

Award: $6,794.23

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: Arabadzhiev

Also found by: ArmedGoose, blutorque

Labels

bug
2 (Med Risk)
high quality report
satisfactory
sponsor acknowledged
edited-by-warden
:robot:_62_group
duplicate-111

Awards

6774.638 USDC - $6,774.64

External Links

Lines of code

https://github.com/code-423n4/2024-02-spectra/blob/main/src/tokens/PrincipalToken.sol#L609 https://github.com/code-423n4/2024-02-spectra/blob/main/src/tokens/PrincipalToken.sol#L588

Vulnerability details

Impact

The PrincipalToken allows for easier concentration of a underlying vault's shares in form of the ibt. In the same time, it is possible to take a flashloan for all of the ibt tokens. If enough vault's shares are concentrated in the PT, then it may enable vault reset attack, explained below, partially draining the underlying vault.

Proof of Concept

During the lifecycle of an ERC4626 vault, it's shares price related to underlying asset slowly increases. The initial ratio is usually 1 share per 1 unit of asset, but over time, when vault's supplies grow, the shares become slightly more expensive and for example they cost 1 share for 1.3 or 1.5 unit of an asset.

Now, considering references: Twitter thread by Kankodu, OZ issue 3800

The risk of "resetting" the vault exist, if vault shares liquidity is concentrated and someone could redeem most of the shares at once, e.g. by a flashloan, resetting the vault, and depositing assets at discounted price. Then, user can return the shares which are "bought" for less assets, repaying the flashloan and keeping the profit.

Since the protocol aims to gain popularity and each PT is dedicated to one specific vault, it should be considered a real risk, that if a vault becomes popular at a PT, which means, it's shares' liquidity is intensely concentrated in form of ibts, which is incentivized, then the vault may be attacked this way.

The flow of the attack is following:

  • an ERC4626 vault, which gains popularity with Spectra, grows large. At some point the share price is 1.5 per 1 asset unit
  • the vault has a corresponding PT where large amount of shares is stored as IBT
  • now, anyone can take a flashLoan for max IBT balance.
  • during the flashloan, attacker redeems IBT in the underlying vault for assets, almost emptying the vault.
  • As the share price drops close to 1:1, user deposits assets again, gaining more than initially shares (IBTs)
  • Attacker repays the flashloans, keeping the profit
  • As per the reference, the profit is: total flashloan value in asset minus fees * (initial share price - reseted share price)

Tools Used

Manual approach.

If flashloans are to be used, consider limiting their amount to only a percentage of IBT balance, instead of full contract balance.

Assessed type

ERC4626

#0 - c4-pre-sort

2024-03-03T10:48:32Z

gzeon-c4 marked the issue as primary issue

#1 - c4-pre-sort

2024-03-03T10:48:36Z

gzeon-c4 marked the issue as high quality report

#2 - gzeon-c4

2024-03-03T10:49:24Z

attack likelihood is pretty low (require all ibt in this contract or the attacker have access to the rest)

#3 - c4-sponsor

2024-03-06T15:33:18Z

yanisepfl (sponsor) disputed

#4 - yanisepfl

2024-03-06T15:33:21Z

As the share price drops close to 1:1, user deposits assets again, gaining more than initially shares (IBTs)

Even if the liquidity was entirely concentrated in our protocol, and the IBT rate does indeed drop to 1, the user would get more IBTs than initially indeed, but those IBTs worth in assets will remain the same as the initial lower amount of IBTs with a higher rate.

Note: we have also considered many other attack vectors with the same hypothesis (where the IBTs are mostly concentrated in our PT vault) but different PoCs, and none of them lead to harming our protocol.

Therefore, the issue reported is wrong and disputed.

#5 - c4-judge

2024-03-11T01:10:50Z

JustDravee marked the issue as unsatisfactory: Invalid

#6 - Arabadzhiew

2024-03-12T08:27:20Z

Hey @JustDravee, thank you for your work!

I believe that this issue was misjudged. The following statement provided by the sponsor seems to be incorrect:

Even if the liquidity was entirely concentrated in our protocol, and the IBT rate does indeed drop to 1, the user would get more IBTs than initially indeed, but those IBTs worth in assets will remain the same as the initial lower amount of IBTs with a higher rate.

The core idea of this issue is that when a malicious user redeems all of the shares they borrowed and resets the IBT vault rate to 1, they are simply going to mint back an amount of IBT shares that is equal to the borrowed amount + flash loan fees, repay those to protocol and keep the difference in assets for themselves. They are not going to mint more shares at the lower rate and pay those back, since that is not required from them at all.

Issue #111 has a coded PoC that demonstrates exactly how this vulnerability can be exploited. I am also not sure why this issue (#240) was selected as the primary one instead of the one I just mentioned, but perhaps you can elaborate more on that.

#7 - blutorque

2024-03-12T17:36:20Z

Drop in IBTRate does profit the attacker and also do affect the protocol users.

Say you have 1000 IBTs backed by $2000 worth of USDT in an yield generating ERC4626 vault, the ratio of share to underlying is 1:2(which initially was 1:1 like any other vault).

As the sponsor said,

Note: we have also considered many other attack vectors with the same hypothesis (where the IBTs are mostly concentrated in our PT vault) but different PoCs, and none of them lead to harming our protocol.

Since, those IBTs are completely hold by PrincipalToken. Any user can claim the ownership of 1000 IBTs via flashloan, and redeem them all for the underlying. Now the attacker only required 1000 USDT to mint 1000 IBTs(since totalSupply==0), with which attacker can repay his debt.

So in total from IBTs vault, attacker manage to steal $1000 worth USDT.

My report #62 explains further ahead, How this actually affect the spectra user who have not claimed their yield yet.

Since, IBTRate drop back to 1. Attacker further calls updateYield function for any user,

    function updateYield(address _user) public override returns (uint256 updatedUserYieldInIBT) {
        (uint256 _ptRate, uint256 _ibtRate) = _updatePTandIBTRates();
    ...snip...

The purpose of doing that is to update the global ptRate and ibtRate via _updatePTandIBTRates(),

Since, ibtRate was dropped by 50% already, the ptRate will also drop to 50%,

        uint256 currentPTRate = currentIBTRate < ibtRate
            ? ptRate.mulDiv(
                currentIBTRate,
                ibtRate,
                roundUpPTRate ? Math.Rounding.Ceil : Math.Rounding.Floor
            )
t0t1t2
ptRate110.5
ibtRate121

This results in negative yield from ibtRate, https://github.com/code-423n4/2024-02-spectra/blob/383202d0b84985122fe1ba53cfbbb68f18ba3986/src/libraries/PrincipalTokenUtil.sol#L104-L107

as well as the less yield from the ptRate for user deposited at t1, https://github.com/code-423n4/2024-02-spectra/blob/383202d0b84985122fe1ba53cfbbb68f18ba3986/src/libraries/PrincipalTokenUtil.sol#L98-L103

#8 - kazantseff

2024-03-12T18:09:36Z

It looks like that this issue of ERC4626 vault price reset is the vulnerability in the implementation of the underlying ERC4626 vault itself, which should be out of scope, or am I missing something? It was also addressed and fixed here, it seems https://github.com/OpenZeppelin/openzeppelin-contracts/issues/3800 https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3979

#9 - Arabadzhiew

2024-03-12T22:24:06Z

@kazantseff Quoting what is stated in the contest README:

The protocol is expected to interact with any ERC4626 compliant vault.

So essentially, what you are saying is the same as saying that vulnerabilities that are arising from ERC20 token integrations are out of scope for a given contest, since those are "vulnerabilities in the implementations of the underlying ERC20 tokens themself", even if it is said that the protocol is intended to interact with any ERC20 tokens.

Additionally, from what I can see this flaw is still present in the most recent ERC4626 OZ implementation (not that this matters).

#10 - kazantseff

2024-03-12T22:41:49Z

@Arabadzhiew It was stated multiple times by a team that such issues are considered out of scope, since integrated IBTs will be monitored by the team, and it's up to the users to check if the IBT they put their money in is safe. image I feel like many issue could have been submitted based on vulnerabilities arising because of a 'wrong' or 'faulty' ERC4626 implementation, but at the end of the day we were auditing an ERC5095 PT contract, not an underlying vault it's being built on top, but that's just my opinion, the judge of course will have a final say.

#11 - Arabadzhiew

2024-03-12T22:57:01Z

You are referring to something completely different. The issue at question is not reliant on a malicious vault implementation at all. In fact, the issue will be present when integrating with completely normal and fair-functioning vaults. That is why I have used the OpenZeppelin ERC4626 implementation as an example in my report.

#12 - blutorque

2024-03-13T02:47:47Z

I feel like many issue could have been submitted based on vulnerabilities arising because of a 'wrong' or 'faulty' ERC4626 implementation,

But we never considered ERC4626 vault as faulty, as said before, either the supply is all in one place or the attacker own the whole,

Also check this comment, from sponser

Note: we have also considered many other attack vectors with the same hypothesis (where the IBTs are mostly concentrated in our PT vault) but different PoCs, and none of them lead to harming our protocol.

they tested the same hypothesis but unable to harm the protocol. We showed them how exactly under certain condition, this bug is exploitable.

Even with the legit vault, this could be a problem, also SS from contest channel

screenshot-220

#13 - yanisepfl

2024-03-15T10:34:38Z

Hello all,

Thanks for the interesting conversation.

After discussing this issue and https://github.com/code-423n4/2024-02-spectra-findings/issues/111 with the team, we came to the conclusion that:

  • Having all the IBTs concentrated in our PTs is a very uncommon scenario. In particular, the usefulness of Spectra also relies on markets and if most of the IBTs are in our vaults then that would imply none or few are used as liquidity in the markets.
  • As it was rightly mentioned by @kazantseff, it is mostly an issue on the IBT 4626 not to be protected against vault price resets. Our protocol is neutral, notices the rate change and act accordingly (as per our design).

We therefore consider it a low or medium severity issue.

Concerning the mitigation, we believe there is no better solution than to have dead shares. The mitigation proposed in https://github.com/code-423n4/2024-02-spectra-findings/issues/111 is too restrictive (e.g. imprecisions) and the one proposed here wouldn’t work depending on the attacker’s PTs/YTs/IBTs ownership.

I hope this helps!

Edit: We acknowledge this issue. It will be clearly specified in our UI and documentations that users should be careful where they invest their funds. In particular, they are expected to make sure the IBTs follow the ERC 4626 and that their rate cannot be easily controlled by someone (e.g. price reset attack, see https://github.com/OpenZeppelin/openzeppelin-contracts/issues/3800 & https://github.com/OpenZeppelin/openzeppelin-contracts/pull/3979). In particular, the PoC provided here does not work on Open Zeppelin's 4626.

#14 - c4-judge

2024-03-15T11:34:32Z

JustDravee removed the grade

#15 - c4-judge

2024-03-15T11:35:03Z

JustDravee marked issue #111 as primary and marked this issue as a duplicate of 111

#16 - c4-judge

2024-03-15T12:00:31Z

JustDravee marked the issue as satisfactory

Findings Information

Labels

bug
grade-b
QA (Quality Assurance)
sufficient quality report
edited-by-warden
Q-07

Awards

19.5868 USDC - $19.59

External Links

[L-01] The pause blocks withdrawals

The PrincipalToken is pausable however the pause stops the protocol completely. That means, even if users might want to redeem their funds, they will not be able to do so, which is a funds freeze for them, inflicting potential loss as they cannot withdraw / sell them.

However some protocols choose such design consciously, accepting the risk. In an ideal world, pause stops entering the protocol but allows for exiting it. But on the other hand, the complete emergency pause allows for stopping the whole protocol and potentially stop an entire attack.

Recommendation: Consider, if allowing users to exit the protocol during pause is acceptable for you.

[L-02] Lack of slippage control on claimFees

Function claimFees does not have option to specify or force a minimum amount accepted as fees. It just blindly redeems the ibts equal to amount of fees, sets remaining fees to 0 and the recovered amount of assets is sent to fee collector.

However it should be kept in mind that redeeming from a vault might be subject to volatility, and ability to set a maximal slippage e.g. 5-10% would rule out a possibility where fee collector will redeem almost nothing due to slippage.

On the other hand, the amounts recovered from that source are probably not going to be significant, which might not incentive sandwichers, thus some losses may occur only due to organic volatility.

Recommendation: Consider adding ability to specify % slippage, minimal amount, or set it to auto, if fee claiming is meant to be autonomous.

[I-01] Consider adding a rescue/sweep function

The PrincipalToken contract is used to transfer tokens to it. The flashloan function has a placeholder to custom token address. However, there is no utility to rescue tokens which might be sent to the contract. A function allowing the DAO for example to claim dust balance, but not considering IBTs or fees, might be helpful to prevent dust or mistakenly transferred tokens to be stuck on the contract.

#0 - c4-pre-sort

2024-03-03T13:55:13Z

gzeon-c4 marked the issue as sufficient quality report

#1 - c4-judge

2024-03-11T01:46:23Z

JustDravee marked the issue as grade-b

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