
Date: October 1, 2026
Chain: Ethereum
Loss: 114.096 WETH, about $305K
Class: a caller check that asked the caller to vouch for itself, plus a raw call to a caller-chosen target
At 14:15 UTC on October 1, 2026, a fresh Ethereum wallet received 0.049875 ETH out of Railgun, a privacy protocol. Less than an hour later that wallet sent one transaction to a contract it had written, and when the transaction finished, two Safe multisigs had lost about 1,313 weETH of collateral and the wallet held 114.096 WETH, worth about $305,000.
The Safes had never signed anything for the attacker. They had enabled FlashLoopAdapter, a third-party module for running leveraged Aave v3 positions, and the adapter decided who was allowed to use it by asking the caller whether the adapter was enabled on the caller. A contract that answered yes to that question could make the adapter call into any Safe that had really enabled it.
A leveraged loop on Aave v3 means depositing collateral, borrowing against it, swapping the borrowed asset into more collateral and repeating, then unwinding the same steps in reverse. Doing that from a Safe multisig normally takes a signed owner transaction for every step. FlashLoopAdapter, deployed in July 2026, was a Safe module built to open and close those positions in one call, using flash loans to do the borrowing and repaying inside a single transaction.
Safe modules are how that becomes possible. When a Safe's owners enable a module, the module can call execTransactionFromModule on the Safe and have the Safe execute a transaction with no further signatures. That's a lot of trust, so a module has to be careful about who it acts for. FlashLoopAdapter's open() and close() functions were meant to act only for a Safe that had enabled the adapter, on that Safe's own position.
According to SlowMist, open() and close() authenticated the caller with one test, whether ISafe(msg.sender).isModuleEnabled(address(this)) returned true. msg.sender is whoever is calling. A real Safe answers that question honestly, but any contract can implement a function called isModuleEnabled that returns true, and the adapter had no other way of knowing whether the caller was a Safe at all.
That alone let a stranger reach the adapter's logic. The second flaw decided what that stranger could do with it. The adapter's internal _swap() made a raw low-level call to a swapRouter address with swapCalldata, and both came from the caller, with no allowlist on the target and no limit on the data. The swap step was supposed to hit a DEX router, but nothing stopped the caller from pointing it at a victim Safe and filling the calldata with execTransactionFromModule. The victim Safe would see a call from a module it had enabled and do what it was told.
Picture a bank's phone line that confirms a caller's identity by asking whether they're an authorized signer on the account, and accepts a yes. The same line then lets that caller dictate a payment order on the bank's letterhead to any business that banks there, and those businesses pay because the letterhead is real. The idea to take from this case is that a contract has to establish who its caller is from state it controls, and anything it forwards on a caller's behalf runs with the contract's own authority, so the target and the data both need limits.
The attacker's wallet, 0x42c2...9353, deployed a helper contract at 14:44 UTC and sent the exploit transaction at 15:08:47 UTC in block 26,098,264, to an attack contract at 0xF091...67ff. The DeFiHackLabs proof of concept describes that contract as playing several parts at once, a fake Safe that answers yes to the module check, a fake flash-loan provider and a fake pool, with no-op behavior everywhere else.
The transaction's token transfers show the rest. The attack contract borrowed 11,537.24 WETH from Morpho Blue in a flash loan and called the adapter as the fake Safe, setting the swap router to a real victim Safe and the calldata to execTransactionFromModule. Through that path it repaid 1,335.26 WETH of Aave debt owed by the first victim Safe, 0xCFeD...169f, which freed its collateral, and moved the Safe's 1,306.48 weETH of Aave collateral to the attack contract. It then pulled 6.43 weETH that the second Safe, 0xE3b2...8520, held directly. The weETH was swapped back to WETH through a Curve weETH/WETH pool and ParaSwap's Augustus router, the flash loan was repaid, and 114.096 WETH went to the attacker's wallet.
Defimon's alert put the loss at about $305,000. The PoC reproduces the 114.096 WETH net profit exactly, and SlowMist's figure of about 114.09 ETH is the same profit net of gas.
At 16:45:59 UTC, the attacker sent 114.13 ETH to a second wallet, 0x951A...2f1a, which forwarded 114.03 ETH into Railgun a minute later. That's the same privacy protocol that funded the attack.
Aave's founder Stani Kulechov described the contract as a "third party external adapter built on top of Aave" with "zero effect on Aave v3," as Cointelegraph reported, and SlowMist confirmed Aave v3's own contracts weren't affected. At 21:03 UTC, an address registered as aavechan.eth sent the attacker an on-chain message saying its owner held the two drained Safes, offering a 10% whitehat bounty of 11.41 ETH if the remaining 102.69 ETH came back by October 3 at 18:00 UTC. As of October 19, 2026, that address, 0x329c...3eD4, hadn't received any ETH back on chain since the message went out.
Olympix reads a contract the way an attacker does, as states, transitions and entry points, and takes in the context around it, here a Safe module whose whole job is to act with the authority Safes delegate to it. From that it infers the invariants the system depends on. For FlashLoopAdapter the invariant is one sentence long: the adapter only moves a Safe's assets when that Safe itself initiated the call.
Olympix's static analysis surfaces two signals in this contract. The first is an authorization check whose only input is a value returned by msg.sender, so the caller is grading its own test. The second is a low-level call whose target and calldata both arrive from the caller with no allowlist, sitting in a contract that other contracts trust as a module. Either signal narrows the search from every path through open() and close(), to the feasible ones, to the paths where the adapter ends up calling a Safe that never called it.
BugPoCer starts from the invariant and works outward through the adapter's entry points, using Counterexample-Guided Invariant Refutation to look for any sequence where a Safe's assets move without that Safe calling in. The counterexample here needs nothing exotic: a contract whose isModuleEnabled() returns true calls open(), names a victim Safe as the swap router and passes execTransactionFromModule as the calldata, and the victim's collateral leaves. BugPoCer returns that as a concrete sequence of state changes with the minimal conditions that trigger it and a generated Forge test that replays it, which is the October 1 drain produced in development.
Olympix has flagged both classes before in other codebases, missing access control and arbitrary external calls to caller-supplied targets. Integration contracts like this one sit between protocols that each work correctly on their own, and the gap only shows up in what the integration accepts as proof of identity. The engine runs in development, at every merge and before release, so that question gets asked of every entry point each time the code changes.
FlashLoopAdapter was trusted by real Safes to act on their behalf, and it extended that trust to any contract willing to claim it. Teams building modules, adapters and routers on top of protocols like Aave and Safe should treat every value the caller supplies, including its answers to questions about itself, as attacker-controlled, and constrain every call made in their own name. To watch Olympix test the authorization paths in your own modules and return a runnable counterexample for any that let the wrong caller through, book a technical walkthrough.
Protocol: FlashLoopAdapter, a third-party Safe module for Aave v3 leveraged loops
Chain: Ethereum
Date: October 1, 2026, 15:08:47 UTC
Loss: 114.096 WETH (about $305K)
Attacker EOA: 0x42c2...9353
Attack contract (fake Safe): 0xF091...67ff
FlashLoopAdapter (victim module): 0x16bb...83d8
Victim Safe 1 (Aave position): 0xCFeD...169f
Victim Safe 2 (weETH holdings): 0xE3b2...8520
Exploit tx: 0x7532...6fc4
Block: 26,098,264
Funding tx (from Railgun, 14:15:23 UTC): 0xc5dc...852b
Transfer to second wallet: 0x3a56...53f9
Second wallet: 0x951A...2f1a
Deposit into Railgun: 0xa206...6dc9
On-chain bounty message from aavechan.eth: 0x94b6...89d0
Flash loan source (Morpho Blue): 0xBBBB...FFCb
SlowMist on X: FlashLoopAdapter Exploit Analysis
SlowMist on X: Aave V3 Contracts Not Affected
Defimon Alerts on X: FlashLoopAdapter Exploit Alert
DeFiHackLabs PR #1287: FlashLoopAdapter Exploit PoC
Cointelegraph: Aave V3 Third-Party Adapter Exploit Drains $305K