Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Any arbitraryCall gathered airdrop can be stolen with recoverTokens #162

Open
code423n4 opened this issue Dec 6, 2021 · 2 comments
Open
Labels
2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working sponsor disputed Sponsor cannot duplicate the issue, or otherwise disagrees this is an issue

Comments

@code423n4
Copy link
Contributor

Handle

hyh

Vulnerability details

Impact

Any airdrop gathered with arbitraryCall will be immediately lost as an attacker can track arbitraryCall transactions and back run them with calls to recoverTokens, which doesn't track any tokens besides reward, deposit and incentive tokens, and will give the airdrop away.

Proof of Concept

arbitraryCall requires that tokens to be gathered shouldn't be reward, deposit or incentive tokens:
https://github.com/code-423n4/2021-11-streaming/blob/main/Streaming/src/Locke.sol#L735

Also, the function doesn't mark gathered tokens in any way. Thus, the airdrop is freely accessible for anyone to be withdrawn with recoverTokens:
https://github.com/code-423n4/2021-11-streaming/blob/main/Streaming/src/Locke.sol#L687

Recommended Mitigation Steps

Add airdrop tokens balance mapping, record what is gathered in arbitraryCall and prohibit their free withdrawal in recoverTokens similarly to incentives[].

Now:

mapping (address => uint112) public incentives;
...
function recoverTokens(address token, address recipient) public lock {
...
		if (incentives[token] > 0) {
			...
			uint256 excess = ERC20(token).balanceOf(address(this)) - incentives[token];
			...
		}

To be:

mapping (address => uint112) public incentives;
mapping (address => uint112) public airdrops;
...
function recoverTokens(address token, address recipient) public lock {
...
		if (incentives[token] > 0) {
			...
			uint256 excess = ERC20(token).balanceOf(address(this)) - incentives[token];
			...
		}
		if (airdrops[token] > 0) {
			...
			uint256 excess = ERC20(token).balanceOf(address(this)) - airdrops[token];
			...
		}
...
// we do know what airdrop token will be gathered
function arbitraryCall(address who, bytes memory data, address token) public lock externallyGoverned {
		...

		// get token balances
		uint256 preDepositTokenBalance = ERC20(depositToken).balanceOf(address(this));
		uint256 preRewardTokenBalance = ERC20(rewardToken).balanceOf(address(this));
		uint256 preAirdropBalance = ERC20(token).balanceOf(address(this));

		(bool success, bytes memory _ret) = who.call(data);
		require(success);
		
		uint256 postAirdropBalance = ERC20(token).balanceOf(address(this));
		require(postAirdropBalance <= type(uint112).max, "air_112");
		uint112 amt = uint112(postAirdropBalance - preAirdropBalance);
		require(amt > 0, "air");
		airdrops[token] += amt;
@code423n4 code423n4 added 3 (High Risk) Assets can be stolen/lost/compromised directly bug Something isn't working labels Dec 6, 2021
code423n4 added a commit that referenced this issue Dec 6, 2021
@brockelmore
Copy link
Collaborator

The intention is that the claim airdrop + transfer is done atomically. Compound-style governance contracts come with this ability out of the box.

@brockelmore brockelmore added the sponsor disputed Sponsor cannot duplicate the issue, or otherwise disagrees this is an issue label Dec 6, 2021
@0xean 0xean added 2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value and removed 3 (High Risk) Assets can be stolen/lost/compromised directly labels Jan 15, 2022
@0xean
Copy link
Collaborator

0xean commented Jan 15, 2022

Going to agree with the warden that as the code is written this is an appropriate risk to call out and be aware of. Downgrading in severity because it relies on external factors but there is no on chain enforcement that this call will be operated correctly and therefore believe it represent a valid concern even if the Sponsor has a mitigation plan in place.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working sponsor disputed Sponsor cannot duplicate the issue, or otherwise disagrees this is an issue
Projects
None yet
Development

No branches or pull requests

3 participants