Silo Finance Incident: A Costly Test
Silo Finance is a decentralized lending platform that enables users to lend and borrow cryptocurrencies in a secure and efficient manner. On June 25, 2025, it was involved in an incident where a testing contract was mistakenly deployed on mainnet, resulting in a loss of approximately $546,000.
Overview
Attacker address: 0x04377cfaf4b4a44bb84042218cdda4cebcf8fd62
Attacker contract: 0x79c5c002410a67ac7a0cde2c2217c3f560859c7e (MalCoin)
Vulnerable contact: LeverageUsingSiloFlashloanWithGeneralSwap
Attack transactions:
Analysis
There were two attack transactions, but the majority of assets were stolen through the first one, so our analysis will focus on that.
Let’s start with LeverageUsingSiloFlashloanWithGeneralSwap - an unreleased feature contract that was deployed on-chain roughly a week before the incident. It was designed to help users maximize profit by executing a flashloan immediately followed by a swap - inherently risky, of course.
The attack begins when the attacker’s contract calls openLeveragePosition()
with fully controlled arguments. This triggers a flashloan()
from MalCoin, ultimately invoking the onFlashLoan()
callback of LeverageUsingSiloFlashloanWithGeneralSwap.
During the callback, LeverageUsingSiloFlashloanWithGeneralSwap uses ExchainProxy to borrow 224 ETH from Silo.
You may have already noticed that the borrow()
method returns approximately 224 shares - the correct amount the borrower is expected to repay for the flashloan. However, LeverageUsingSiloFlashloanWithGeneralSwap makes a critical mistake: it ignores the return value of borrow()
and instead relies on the current balance of the buyToken
(which is MalCoin in this case) to determine amountOut
.
At this point, MalCoin maliciously returns a constant balance of 1
for all accounts, allowing the attacker to drain the ETH without repaying (almost) anything.
Conclusion
This incident highlights the dangers of leaving test code or assumptions in production deployments, which led to a significant and preventable loss of funds. To mitigate such risks in the future, it is essential to separate test logic from production code, conduct thorough audits before deployment, implement stricter deployment checks and code reviews, and use more realistic scenarios during testing to better simulate mainnet behavior. A disciplined development process combined with proper auditing is critical to ensuring contract safety and protecting user funds.