51283 sc critical permanent freeze of user token due to unhandled partial fill refunds for swap via 1inch in dexaggregatorwrapperwithpredicateproxy

Submitted on Aug 1st 2025 at 12:08:18 UTC by @perseverance for Attackathon | Plume Network

  • Report ID: #51283

  • Report Type: Smart Contract

  • Report severity: Critical

  • Target: https://github.com/immunefi-team/attackathon-plume-network-nucleus-boring-vault/blob/main/src/helper/DexAggregatorWrapperWithPredicateProxy.sol

  • Impacts: Permanent freezing of funds

Description

Short summary

The DexAggregatorWrapperWithPredicateProxy.sol contract is vulnerable to a permanent freeze of user funds when interacting with the 1inch DEX aggregator. If a user initiates a swap using the depositOneInch or depositAndBridgeOneInch function and includes the _PARTIAL_FILL flag in the swap parameters, any unspent token refunded by 1inch is sent back to the proxy contract. The proxy contract has no mechanism to withdraw, unwrap, or transfer this returned token, causing the user's funds to be permanently and irreversibly locked within the contract.

The vulnerability

The core issue is that depositOneInch / depositAndBridgeOneInch do not account for 1inch's partial-fill refund behavior. When _PARTIAL_FILL is set in AggregationRouterV6.SwapDescription, the 1inch router refunds unused source tokens to msg.sender. In this integration, msg.sender is the proxy contract. The proxy:

  • receives the refunded ERC20 (e.g., WETH),

  • has no function to unwrap WETH to ETH,

  • has no generic sweep/transfer for arbitrary ERC20 tokens,

  • does not forward the refunded token back to the user.

Consequently, refunded tokens remain trapped in the proxy contract permanently.

Relevant contract locations:

  • Proxy: https://github.com/immunefi-team/attackathon-plume-network-nucleus-boring-vault/blob/main/src/helper/DexAggregatorWrapperWithPredicateProxy.sol

  • 1inch Aggregation router: https://etherscan.io/address/0x111111125421ca6dc452d289314280a0f8842a65#code

Vulnerable excerpt from depositOneInch:

Vulnerable excerpt from _oneInchHelper:

1inch refund logic (relevant excerpt from AggregationRouterV6):

Because the router refunds the unused srcToken to msg.sender (the proxy contract), any unspent WETH / depositAsset is transferred to the proxy and becomes irrecoverable given the proxy's missing recovery/unwrapping logic.

Severity assessment

Suggested remediation

Proof of Concept (Conceptual)

This scenario demonstrates the permanent loss of funds.

1

Step

User's Action: A user ("Victim") wants to swap 10 ETH for USDC, but is willing to accept a partial fill. They call depositOneInch with desc including the _PARTIAL_FILL flag and send msg.value = 10 ether.

2

Step

Proxy's Action: The DexAggregatorWrapperWithPredicateProxy receives 10 ETH, wraps it into 10 WETH (if using native flow), and calls the 1inch aggregator swap.

3

Step

1inch Action: The 1inch aggregator partially fills 7 WETH -> USDC and, because _PARTIAL_FILL is set, refunds the remaining 3 WETH to msg.sender (the proxy contract).

4

Step

Consequence: The proxy contract now holds 3 WETH. The proxy has no function to unwrap or transfer this WETH back to the user or elsewhere. The 3 WETH is permanently trapped.

5

Step

Result: The user receives shares corresponding to the 7 WETH swap, but the 3 WETH is permanently lost.

Sequence diagram (mermaid):

References

  • 1inch Aggregation router contract: https://etherscan.io/address/0x111111125421ca6dc452d289314280a0f8842a65#code

  • Proxy contract: https://github.com/immunefi-team/attackathon-plume-network-nucleus-boring-vault/blob/main/src/helper/DexAggregatorWrapperWithPredicateProxy.sol

(End of report)

Was this helpful?