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

Improper Handling of msg.value in ETH Pool Join Operations #329

Closed
howlbot-integration bot opened this issue Aug 20, 2024 · 4 comments
Closed

Improper Handling of msg.value in ETH Pool Join Operations #329

howlbot-integration bot opened this issue Aug 20, 2024 · 4 comments
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 duplicate-70 edited-by-warden 🤖_59_group AI based duplicate group recommendation satisfactory satisfies C4 submission criteria; eligible for awards sufficient quality report This report is of sufficient quality

Comments

@howlbot-integration
Copy link

Lines of code

https://github.com/code-423n4/2024-07-loopfi/blob/57871f64bdea450c1f04c9a53dc1a78223719164/src/proxy/PoolAction.sol#L142

Vulnerability details

Description

The identified vulnerability pertains to the improper handling of msg.value within the join() function, particularly when users attempt to join a Balancer pool using ETH. This flaw arises from the function’s failure to correctly manage the msg.value parameter, which represents the amount of ETH sent by the user. As a result, the ETH provided by the user may be sent to the contract or Vault but remains unwrapped and unutilized in the intended pool join operation, leading to substantial financial loss and user dissatisfaction.

The Balancer protocol supports users joining liquidity pools using various tokens, including ETH. Typically, when a user sends ETH, it is wrapped into WETH via the balancerVault.joinPool() function and subsequently added to the pool. This process hinges on the correct forwarding of the msg.value parameter from the join() function to the balancerVault.joinPool() function.

However, the vulnerability manifests when the join() function neglects to properly pass the msg.value to the balancerVault.joinPool() function. In such instances, while the ETH is received by the contract or Vault, it is neither wrapped into WETH nor added to the pool. This erroneous handling can lead to two primary issues:

  • Loss of Funds: The ETH provided by the user becomes trapped within the contract or Vault, as it is not employed in the pool join operation. Consequently, the user does not receive the corresponding pool shares, effectively losing the ETH they intended to use.

Proof of Concept

  • Scenario: Alice intends to join a Balancer pool by sending 50 ETH. She calls the join() function, anticipating that her ETH will be wrapped into WETH and used to join the pool.

  • Flawed Execution: Alice’s 50 ETH is correctly sent as msg.value to the join() function. However, due to an improper implementation, the msg.value is not passed to the balancerVault.joinPool() function as required.

  • Outcome: The ETH is received by the contract or Vault but remains unwrapped and unutilized in the pool join operation. Consequently, the joinPool function does not recognize any ETH being sent, and no pool shares are issued to Alice. Her 50 ETH is effectively trapped within the contract or Vault, resulting in a total loss of funds.

function _balancerJoin(PoolActionParams memory poolActionParams) internal {
    (bytes32 poolId, address[] memory assets, uint256[] memory assetsIn, uint256[] memory maxAmountsIn) = abi.decode(
        poolActionParams.args, (bytes32, address[], uint256[], uint256[])
    );
    for (uint256 i = 0; i < assets.length; ) {
        if (maxAmountsIn[i] != 0) {
            IERC20(assets[i]).forceApprove(address(balancerVault), maxAmountsIn[i]);
        }
        unchecked {
            ++i;
        }
    }
    balancerVault.joinPool(     <-------
        poolId,
        address(this),
        poolActionParams.recipient,
        IBalancerVault.JoinPoolRequest({
            assets: assets,
            maxAmountsIn: maxAmountsIn,
            userData: userData,
            fromInternalBalance: false
        })
    );
}

The key issue lies in the absence of an explicit forwarding of msg.value to the balancerVault.joinPool() function, which is crucial for the proper handling of ETH in pool join operations.

Impact

The impact of this vulnerability is considerable. Users who attempt to join pools using ETH risk losing their funds due to the improper handling of msg.value. The ETH provided by users is not converted into WETH or added to the liquidity pool, resulting in the loss of both the ETH and the expected pool shares. This scenario not only leads to financial loss but also damages user trust in the protocol, as the transaction behavior deviates from expected outcomes.

Tools Used

Manual Review, related issue - https://solodit.xyz/issues/h-6-msgvalue-will-not-be-populated-if-eth-is-the-secondary-token-sherlock-notional-notional-update-git

Recommended Mitigation Steps

To mitigate this vulnerability, it is imperative to ensure that the join() function correctly forwards msg.value to the balancerVault.joinPool() function whenever ETH is sent. This can be achieved by explicitly including the msg.value in the joinPool call, as demonstrated in the following code example:

balancerVault.joinPool{value: msg.value}(
    poolId,
    address(this),
    poolActionParams.recipient,
    IBalancerVault.JoinPoolRequest({
        assets: assets,
        maxAmountsIn: maxAmountsIn,
        userData: abi.encode(JoinKind.EXACT_TOKENS_IN_FOR_BPT_OUT, assetsIn, poolActionParams.minOut),
        fromInternalBalance: false
    })
);

Assessed type

Payable

@howlbot-integration howlbot-integration bot added 2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value 🤖_59_group AI based duplicate group recommendation bug Something isn't working duplicate-69 edited-by-warden sufficient quality report This report is of sufficient quality labels Aug 20, 2024
howlbot-integration bot added a commit that referenced this issue Aug 20, 2024
@c4-judge c4-judge added downgraded by judge Judge downgraded the risk level of this issue QA (Quality Assurance) Assets are not at risk. State handling, function incorrect as to spec, issues with clarity, syntax and removed 2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value labels Oct 1, 2024
@c4-judge
Copy link
Contributor

c4-judge commented Oct 1, 2024

koolexcrypto changed the severity to QA (Quality Assurance)

@c4-judge c4-judge reopened this Oct 1, 2024
@c4-judge c4-judge added 2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value and removed downgraded by judge Judge downgraded the risk level of this issue QA (Quality Assurance) Assets are not at risk. State handling, function incorrect as to spec, issues with clarity, syntax labels Oct 1, 2024
@c4-judge
Copy link
Contributor

c4-judge commented Oct 1, 2024

This previously downgraded issue has been upgraded by koolexcrypto

@c4-judge c4-judge closed this as completed Oct 1, 2024
@c4-judge
Copy link
Contributor

c4-judge commented Oct 1, 2024

koolexcrypto marked the issue as duplicate of #70

@c4-judge c4-judge added duplicate-70 satisfactory satisfies C4 submission criteria; eligible for awards and removed duplicate-69 labels Oct 1, 2024
@c4-judge
Copy link
Contributor

c4-judge commented Oct 1, 2024

koolexcrypto marked the issue as satisfactory

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 duplicate-70 edited-by-warden 🤖_59_group AI based duplicate group recommendation satisfactory satisfies C4 submission criteria; eligible for awards sufficient quality report This report is of sufficient quality
Projects
None yet
Development

No branches or pull requests

1 participant