#55049 [SC-Insight] there is a issue related that the msg value not returned to payer in self close exit
Submitted on Sep 21st 2025 at 17:44:47 UTC by @XDZIBECX for Mitigation Audit | Flare | FAssets
Report ID: #55049
Report Type: Smart Contract
Report severity: Insight
Target: https://github.com/flare-foundation/fassets/commit/03304ecf8110fd32f94620f111e2593f6969d573
Impacts:
Griefing (e.g. no profit motive for an attacker, but damage to the users or the protocol)
Description
Brief / Intro
A change in CollateralPool’s self-close exit flow mis-forwards the caller’s msg.value to the redemption recipient instead of refunding the payer. Any user who includes ETH when no executor is used or when the flow takes the collateral path will lose that ETH to the recipient. In self-close exits, ETH is only needed if an executor is specified for underlying-chain redemption; therefore the function should ignore and refund any attached ETH when an executor is not used. The current code instead forwards this unintended ETH to the redemption recipient whenever no executor is used or when the flow takes the collateral path (for example, redeem-to-collateral or requiredFAssets < lotSize). A user who mistakenly includes ETH (due to a UI default or script error) effectively “donates” it to the recipient, causing user loss.
Vulnerability Details
When returnFunds
is true, the contract forwards the caller’s msg.value to the recipient _recipient
instead of refunding the payer (msg.sender
).
Vulnerable snippet:
// redeem f-assets if necessary
bool returnFunds = true;
if (requiredFAssets > 0) {
if (requiredFAssets < assetManager.lotSize() || _redeemToCollateral) {
assetManager.redeemFromAgentInCollateral(agentVault, _recipient, requiredFAssets);
} else {
returnFunds = _executor == address(0);
assetManager.redeemFromAgent{ value: returnFunds ? 0 : msg.value }(
agentVault, _recipient, requiredFAssets, _redeemerUnderlyingAddress, _executor
);
}
}
// ...
if (returnFunds) {
Transfers.transferNAT(_recipient, msg.value); // <-- issue: refunds to recipient instead of payer
}
The accidental msg.value should be refunded to the caller msg.sender
, not gifted to _recipient
.
Impact Details
If users call the self-close exit without an executor or the flow uses the collateral path, any ETH they accidentally attach to the transaction is incorrectly forwarded to the redemption recipient instead of being refunded to them. A simple UI default or script mistake can cause the caller to lose ETH to a third party, producing guaranteed user loss with no benefit to the protocol.
Fix: change the refund target when no executor is used — in _selfCloseExitTo
, replace sending msg.value to _recipient
with refunding it to msg.sender
, ensuring accidental ETH is returned to the payer and removing the griefing risk.
References
https://github.com/flare-foundation/fassets/blob/d274320418134194cf74f69f95326ca40e2c1fed/contracts/collateralPool/implementation/CollateralPool.sol#L309C1-L312C10
Proof of Concept
Recommended Fix
In the code path where returnFunds
is set true (no executor is used and the function did not consume msg.value in redeem call), refund msg.value
to msg.sender
instead of _recipient
. This ensures accidental ETH is returned to the payer.
(Do not change any links or references above.)
Was this helpful?