dHEDGE manager can steal almost all the clients' funds in just one tx

On Feb 6, 2023 we discovered the critical security vulnerability in the dHEDGE protocol allowing a malicious trader or manager to almost fully drain the pool containing the clients’ funds, and submitted it to the dHEDGE via the Immunefi bug bounty platform.

The team decided to close our submission as “won’t fix“, the protocol is still vulnerable. Here we’re sharing the details.

Overview

dHEDGE is, as stated in their docs,

an asset management protocol that facilitates a censorship-resistant and non-custodial connection between individuals seeking to allocate funds and asset managers. It’s an asset management protocol that facilitates a censorship-resistant and non-custodial connection between individuals seeking to allocate funds and asset managers.

There are two main roles in dHedge: an investor, and a manager.

Managers create pools and trade with clients’ funds using a bunch of pre-approved 3rd-party protocols like Uniswap, Aave and so on.

Investors can see all the active pools and their statistics like APY, TVL etc. Then they can invest their funds into the best fitting one to earn with the manager’s trading strategy.

It’s worth a special noting that one of the key focal points of the dHEDGE protocol is

Non-custodial: users retain ownership over their funds, asset managers cannot run away with individuals funds.

Sounds good but it’s a fake statement.

Vulnerability

Every pool is a separate contract that stores the clients’ funds and provides a set of the management functions allowing the pool manager (and a trader, who is a “truncated” manager) to execute various 3rd-party protocols transactions on behalf of the pool. The manager just calls the execTransaction(address to, bytes calldata data) function with necessary contract address and the corresponding calldata and it’s done.

To keep the funds safe from being stolen by a malicious manager (or rather just make it looking like this) the so-called guards are implemented. Thus, only pre-approved contracts and their pre-approved functions are allowed to be executed by a manager. When the execTransaction is called, it gets the corresponding guard contract for the specified to address and the guard checks the calldata passed to ensure the operation is legal.

For instance, for Uniswap swaps it’s checked that the funds recipient is a pool itself (to protect funds from being just transferred away) or the target token is approved to be used within the protocol (to protect funds from being swapped to the malicious fake tokens).

Below is a guard check applied to the UniswapV3 exactInput operation:

if (method == IV3SwapRouter.exactInput.selector) {
      IV3SwapRouter.ExactInputParams memory params = abi.decode(getParams(data), (IV3SwapRouter.ExactInputParams));

      (address srcAsset, address dstAsset) = _decodePath(params.path);
      require(poolManagerLogicAssets.isSupportedAsset(dstAsset), "unsupported destination asset");

      require(pool == params.recipient, "recipient is not pool");

      _checkSlippageLimit(srcAsset, dstAsset, params.amountIn, params.amountOutMinimum, address(poolManagerLogic));

      emit ExchangeFrom(pool, srcAsset, params.amountIn, dstAsset, block.timestamp);

      txType = 2; // 'Exchange' type
    }

Besides the checks I mentioned above, it also checks the resulting slippage to be less than 10% to protect funds from accidentally (or intentionally) being lost by unfavourable swap.

The vulnerability we found here is that despite both input and output tokens are checked to be pre-approved, the intermediate ones are not. Thus, in conjunction with allowed 10% slippage, the malicious manager can steal almost all the clients’ funds by following the next steps:

  • create a fake ERC-20 token FAKE;

  • create two UniswapV3 pools with this fake token and two dHEDGE pre-approved assets, for instance USDT/FAKE and FAKE/USDC and provide the liquidity into them in such a way that swapping 100 USDT with the “USDT → FAKE → USDC“ route would result in 90 USDC;

  • perform such swap operation on behalf of the pool using the execTransaction (it would reduce the pool value on 10% but add it to the malicious Uniswap pools);

  • repeat this process for a few times (after 10 repeats, the stolen liquidity will be about 35%, and after 30 repeats it will be about 96%!);

  • remove all the liquidity from the malicious Uniswap pools and receive stolen USDT.

There are pools having more than $15M TVL now so, if the manager wants, they can steal $1.5M of the clients’ funds in just single operation and at least up to 96% of this pool value ($14.4M) in just a single tx.

You may collect this entry to support our blog and motivate us to share more vulnerabilities we found.

Resolution

The vulnerability found allows a malicious manager to exactly “run away with individuals funds”, that breaks one of the “key focal point“ of the dHEDGE protocol.

However, the team responded that the issue is a well-known one and it’s impossible to fix it “given the nature of onchain asset management protocols“ and the flexibility of the protocol. They provided no evidences of the fact that they had been aware of this though.

As for fixing impossibility, we suggested several options of possible mitigations including:

  • calculating the total pool value loss during the last few transactions and emergency pausing the pool if it seems that the funds are being stolen (this is how Enzyme Finance solves such a problem, for instance) – as the global security improvement;

  • сhecking if the submitted swap path is malicious by calculating the output of the direct swap src → dst. Obviously, if the direct swap is 10% better than the user-submitted path one, then this complicated path's goal is just to steal value – as this current Uniswap issue mitigation.

However, all of these options were just ignored by the team and the final decision on the report was not to fix it but just add a “risk disclaimer” for the users.

We don't know for sure if the disclaimer was added somewhere, but the protocol docs still contains this “key focal point“.
We don't know for sure if the disclaimer was added somewhere, but the protocol docs still contains this “key focal point“.

The issue is closed now and a “goodwill payout“ of $500 is payed out to us, and the protocol is still vulnerable. We requested a mediation from the Immunefi team but since no fix were implemented by the protocol, the only thing the mediation was able to do for us was to recommend dHEDGE to at least increase the goodwill payout amount. The recommendation was also ignored however.

We had notified the dHEDGE team about our intention on disclosing the issue publicly 30 days before this write-up but they didn’t respond.

About Quantish

We don’t perform classic audits but vulnerability research that highlights really severe problems of your code.

If you want us to investigate your protocol, just reach us out on quantish.sec[at]gmail.com

Subscribe to Quantish
Receive the latest updates directly to your inbox.
Mint this entry as an NFT to add it to your collection.
Verification
This entry has been permanently stored onchain and signed by its creator.