-
Notifications
You must be signed in to change notification settings - Fork 1
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
Flash Loan Vulnerability: Potential Unauthorized Transfers during Flash Loan Execution #16
Comments
Hello, We classified this issue as invalid because Thanks |
Hello,
yes, this is true, but the issue is not about malicious The issue is that anyone could call 'flashloanLender:flashLoan' before flash loan repayments. During flash loan repayment, any actor could call Consider the following scenario: Bob wants to get a flash loan and execute some commands before flash loan repayment. During a repayment, any other actor could call function flashLoan(
@@@@> IERC3156FlashBorrower _receiver,
address _token,
uint256 _amount,
bytes calldata _data
) external override whenNotPaused returns (bool) {
if (_amount > maxFlashLoan(_token)) revert FlashLoanExceedsMaxAmount();
uint256 fee = flashFee(_token, _amount);
_updateFees(fee);
// Initiate the flash loan by lending the requested IBT amount
address _ibt = ibt;
IERC20(_ibt).safeTransfer(address(_receiver), _amount);
// Execute the flash loan
@@@@> if (_receiver.onFlashLoan(msg.sender, _token, _amount, fee, _data) != ON_FLASH_LOAN)
revert FlashLoanCallbackFailed();
// Repay the debt + fee
IERC20(_ibt).safeTransferFrom(address(_receiver), address(this), _amount + fee);
return true;
} function onFlashLoan(
@@@@> address /* initiator */,
address _token,
uint256 _amount,
uint256 _fee,
bytes calldata _data
) external returns (bytes32) {
if (msgSender == address(0)) {
revert DirectOnFlashloanCall();
}
if (msg.sender != flashloanLender) {
revert UnauthorizedOnFlashloanCaller();
}
(bytes memory commands, bytes[] memory inputs) = abi.decode(_data, (bytes, bytes[]));
this.execute(commands, inputs); // https://ethereum.stackexchange.com/questions/103437/converting-bytes-memory-to-bytes-calldata
uint256 repayAmount = _amount + _fee;
uint256 allowance = IERC20(_token).allowance(address(this), msg.sender);
if (allowance < repayAmount) {
// Approve the lender to pull the funds if needed
IERC20(_token).forceApprove(msg.sender, repayAmount);
}
uint256 balance = IERC20(_token).balanceOf(address(this));
if (balance < repayAmount) {
// Collect remaining debt from the original sender if needed
@@@@> IERC20(_token).safeTransferFrom(msgSender, address(this), repayAmount - balance);
}
return ON_FLASH_LOAN; There is no check to verify who the The final question here will be who will be the other actor:
Spectra-0x4b792db3d2a5d1c1ccf9938380756b200c240e5d/src/router/Dispatcher.sol Lines 151 to 153 in 06b05fc
Spectra-0x4b792db3d2a5d1c1ccf9938380756b200c240e5d/src/router/Dispatcher.sol Lines 177 to 179 in 06b05fc
Spectra-0x4b792db3d2a5d1c1ccf9938380756b200c240e5d/src/router/Dispatcher.sol Lines 192 to 198 in 06b05fc
Spectra-0x4b792db3d2a5d1c1ccf9938380756b200c240e5d/src/router/Dispatcher.sol Lines 131 to 140 in 06b05fc
|
Hello again,
This is impossible since a flash loan execution happens atomically. No one can execute your scenario's point 4 before before the transaction executed at 3 finished. Thanks again and have a good day |
Github username: @0xmahdirostami
Twitter username: 0xmahdirostami
Submission hash (on-chain): 0x4a7a612fd62ef9364c23b61b1f39f0277f2ed86f38f288f403cc2da0f79386c3
Severity: high
Description:
description
In the current flash loan implementation, the flashloanLender variable is set to the lender's address when a flash loan is initiated and remains unchanged until the loan is completed. This creates a vulnerability where, during subsequent commands in the flash loan transaction, malicious actors could potentially transfer funds without the user’s knowledge.
The vulnerability exists because the onFlashLoan function does not verify that the flash loan initiator matches the Router contract’s address. Since flashloanLender remains unchanged throughout the loan, a malicious actor could execute steps that involve calling the lender’s flashLoan function with the Router contract as the receiver, causing an unauthorized transfer of funds from the user to the lender.
details
after a flash loan command,
flashloanLender
will be assigned to the lender address, and during all upcoming commands, this value will be the same until the end of flash loan execution.Spectra-0x4b792db3d2a5d1c1ccf9938380756b200c240e5d/src/router/Dispatcher.sol
Lines 256 to 263 in 06b05fc
Spectra-0x4b792db3d2a5d1c1ccf9938380756b200c240e5d/src/router/Router.sol
Line 277 in 06b05fc
in any upcoming steps, anyone could call a lender with a router address as a receiver.
Spectra-0x4b792db3d2a5d1c1ccf9938380756b200c240e5d/src/tokens/PrincipalToken.sol
Lines 465 to 466 in 06b05fc
Spectra-0x4b792db3d2a5d1c1ccf9938380756b200c240e5d/src/tokens/PrincipalToken.sol
Lines 481 to 483 in 06b05fc
as flashloanLender has not changed yet and the onFlashLoan function doesn't check
initiator
, anyone could transfer funds from msgSender to lenderSpectra-0x4b792db3d2a5d1c1ccf9938380756b200c240e5d/src/router/Router.sol
Lines 263 to 275 in 06b05fc
Spectra-0x4b792db3d2a5d1c1ccf9938380756b200c240e5d/src/router/Router.sol
Lines 284 to 288 in 06b05fc
Scenario
flashloanLender
variable is set to the trusted lender at the start of the flash loan.flashloanLender
remains unchanged, allowing a malicious target to exploit this state by callinglender::flashLoan
with the Router contract as_receiver
.onFlashLoan
function will not check the initiator and will execute the command as the flashloanLender check passes.Impact
This vulnerability allows unauthorized fund transfers.
mitigation
To secure the flash loan mechanism, implement the following changes:
flashloanLender
after the first call from the lender: Instead of only clearing flashloanLender upon flash loan completion, reset it immediately after the first interaction from the lender.onFlashLoan
: Ensure thatonFlashLoan
only executes commands if the initiator is the Router contract itself. This means the contract should only accept calls initiated byaddress(this)
.Mitigation Code:
The text was updated successfully, but these errors were encountered: