PoolTogether micro contest #1 - GalloDaSballo's results

A protocol for no loss prize savings on Ethereum

General Information

Platform: Code4rena

Start Date: 29/07/2021

Pot Size: $20,000 USDC

Total HM: 8

Participants: 12

Period: 3 days

Judge: LSDan

Total Solo HM: 2

Id: 24

League: ETH

PoolTogether

Findings Distribution

Researcher Performance

Rank: 6/12

Findings: 4

Award: $1,344.95

🌟 Selected for report: 2

πŸš€ Solo Findings: 0

Findings Information

🌟 Selected for report: GalloDaSballo

Also found by: 0xRajeev, gpersoon

Labels

bug
3 (High Risk)
SwappableYieldSource
sponsor disputed

Awards

838.3068 USDC - $838.31

External Links

Handle

GalloDaSballo

Vulnerability details

Impact

The function swapYieldSource https://github.com/pooltogether/swappable-yield-source/blob/89cf66a3e3f8df24a082e1cd0a0e80d08953049c/contracts/SwappableYieldSource.sol#L307

Can be called by the owner (deployer / initializer) or Asset Manager

The function will take all funds from the old Yield Source, and transfer them to the new Yield source.

Any contract that implement the function function depositToken() external returns (address) will pass the check

However, if either the owner or the assetManager have malicious intent, this function allows them to instantly rug all funds

Proof of Concept

  1. Create a contract that implements the function depositToken() external returns (address)
  2. Be the Owner or AssetManager
  3. Call setYieldSource while pointing at your malicious contract
  4. Profit

I highly recommend checking that the YieldSource is from a trusted registry before allowing this swap.

Alternatively forcing each Owner to be a TimeLock with at least 48 hours may provide enough security to allow this to be used in practice

#0 - PierrickGT

2021-08-11T22:11:14Z

This is why we will use a multi sig owned by governance to deploy swappable yield sources and manage them. This way, we will avoid these kind of scenarios.

#1 - 0xean

2021-08-24T18:04:44Z

Agree with warden on the risk here. Will both the AssetManager and the Owner be owned by your governance?

The YieldSource could easily extract user funds or send them back to the SwappableYieldSource contract and then remove them from there.

#2 - PierrickGT

2021-08-30T23:22:11Z

We have removed the AssetManager role and Owner will be owned by governance who will vet any change of yield source before going through a vote.

Findings Information

🌟 Selected for report: tensors

Also found by: GalloDaSballo, cmichel, hickuphh3

Labels

bug
duplicate
1 (Low Risk)
SwappableYieldSource

Awards

169.7571 USDC - $169.76

External Links

Handle

GalloDaSballo

Vulnerability details

Impact

When swapping from one yield source to another, via the function _setYieldSource https://github.com/pooltogether/swappable-yield-source/blob/89cf66a3e3f8df24a082e1cd0a0e80d08953049c/contracts/SwappableYieldSource.sol#L254

You are correctly giving approval to the new yield source. However, since you are retiring the old one, it's probably best to remove the allowance from the old yield source

Change

function _setYieldSource(IYieldSource _newYieldSource) internal { _requireDifferentYieldSource(_newYieldSource); require(_newYieldSource.depositToken() == yieldSource.depositToken(), "SwappableYieldSource/different-deposit-token"); yieldSource = _newYieldSource; IERC20Upgradeable(_newYieldSource.depositToken()).safeApprove(address(_newYieldSource), type(uint256).max); emit SwappableYieldSourceSet(_newYieldSource); }

To

function _setYieldSource(IYieldSource _newYieldSource) internal { _requireDifferentYieldSource(_newYieldSource); require(_newYieldSource.depositToken() == yieldSource.depositToken(), "SwappableYieldSource/different-deposit-token"); IERC20Upgradeable(yieldSource.depositToken()).safeApprove(address(_newYieldSource), 0); yieldSource = _newYieldSource; IERC20Upgradeable(_newYieldSource.depositToken()).safeApprove(address(_newYieldSource), type(uint256).max); emit SwappableYieldSourceSet(_newYieldSource); }

#0 - PierrickGT

2021-08-06T16:08:39Z

Findings Information

🌟 Selected for report: GalloDaSballo

Labels

bug
1 (Low Risk)
SwappableYieldSource
sponsor disputed

Awards

310.484 USDC - $310.48

External Links

Handle

GalloDaSballo

Vulnerability details

Impact

Detailed description of the impact of this finding.

_requireYieldSource https://github.com/pooltogether/swappable-yield-source/blob/89cf66a3e3f8df24a082e1cd0a0e80d08953049c/contracts/SwappableYieldSource.sol#L74

Runs a few checks to see if the function depositToken is implemented Notice that this is not a guarantee that the target is a valid Yield Source.

This will simply verify that the contract has that method.

Any malicious attacker could implement that function and then set up the Yield Source to steal funds

In order to guarantee that the target is a valid Yield Source, you'd want to create a registry of know Yield Sources, perhaps controlled by governance or by the DAO, and check against that.

Proof of Concept

Provide direct links to all referenced code in GitHub. Add screenshots, logs, or any other relevant proof that illustrates the concept.

Create any contract with just a function depositToken returns (address) and you'll be able to add pass the check

Tools Used

Create an on-chain registry of known Yield Sources, either by committee or governance, and use a check against the registry, this will avoid griefing

#0 - PierrickGT

2021-08-11T21:43:14Z

Swappable Yield Sources will be deployed by a multi sig owned by governance, _requireYieldSource function does indeed simply performs a sanity check to be sure that the yield source address passed is implementing the depositToken function. This is to avoid any human error and deploying a swappable yield source that would be unusable cause the address passed wouldn't be a yield source.

Deployments of a new swappable yield source will be voted by governance, as will a change of yield source, so it would be pretty time and gas consuming to have also to add any new yield source we which to switch to to a registry,

#1 - 0xean

2021-08-24T17:07:20Z

Agree with warden that these checks are not sufficient to deter a malicious implementation. Additionally, switching of the yield source looks to be feasible by the owner (presumably the above mentioned multisig) or the AssetManager which is unclear who controls this address. Leaving open.

#2 - PierrickGT

2021-08-30T23:23:11Z

We have removed the AssetManager role and Owner will be owned by governance who will vet any change of yield source before going through a vote.

Findings Information

🌟 Selected for report: hickuphh3

Also found by: 0xRajeev, GalloDaSballo, cmichel, pauliax

Labels

bug
duplicate
0 (Non-critical)
SwappableYieldSource

Awards

26.3992 USDC - $26.40

External Links

Handle

GalloDaSballo

Vulnerability details

Impact

In supplyTokenTo, redeemToken, approveMaxAmount, _setYieldSource, and _transferFunds you write: _yieldSource.depositToken(), however you already defined a public function called depositToken to retrieve the address of the depositToken for the current Yield Source.

Since it's marked public, you could refactor every use of _yieldSource.depositToken()Β to depositToken()

Otherwise, you can mark the function as external so that it's clear it's just supposed to be used from outside

#0 - PierrickGT

2021-08-06T16:31:41Z

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