FujitaChain

The Silo Protocol Exploit: A Forensic Deconstruction of the $45 Million Flash Loan Attack

Press Releases | StackSignal |

The logs went silent at block 19,847,362. No error codes. No reversion. Just a state where the vault’s totalSupply dropped by 45 million USDC while the attacker’s contract balance increased by the same amount. The transaction was a single atomic bundle—four flash loans, two Uniswap swaps, and one critical call to a function named redeemUnderlying. Code doesn’t steal. It executes. The ghost in the smart contract state is never a ghost. It is logic, exploited.

Context: The Silo Protocol and Its Lending Architecture

Silo Protocol launched in early 2024 as a “permissionless lending market” designed for isolated collateral pools. Unlike Aave or Compound, where assets share risk, Silo allowed users to create isolated lending pairs—each silo was a separate contract with its own oracle, interest rate model, and liquidation parameters. The promise was simple: compartmentalize risk so a single asset collapse wouldn’t cascade. The architecture was audited by three firms—Trail of Bits, ConsenSys Diligence, and SlowMist. All gave green lights. The market cap of total value locked peaked at $1.2 billion in March 2025.

But audits are snapshots of known attack vectors. They do not measure adversarial creativity. On April 14, 2025, an attacker drained 45 million USDC from the USDC-ETH silo in a single transaction. The transaction cost was $0.14 in gas. The attack took 3.2 seconds from first flash loan to final token transfer.

Core: The Multi-Function Exploit Path

Tracing the Ghost in the Smart Contract State

I reconstructed the attack using Etherscan archival node data and Foundry’s debugger. The exploit leveraged three distinct vulnerabilities—each individually low risk, but combinatorially devastating.

Vulnerability #1: Oracle Price Manipulation via Uniswap V3 TWAP Lag

Silo’s oracle used a 30-minute time-weighted average price from Uniswap V3. The contract calculated twapPrice = oracle.getTWAP(siloToken, baseToken, 1800 seconds). The attacker manipulated the spot price of a low-liquidity pair (USDC/DAI) on Uniswap V3 in a single block, driving the spot price to 0.98 USDC per DAI (normally 1.00). The TWAP function, however, used the last 30-minute window, which meant the short-term manipulation could not affect the TWAP directly. But the vulnerability was not in TWAP calculation. It was in the fallback path.

Silo’s code had a getPrice() function that checked the on-chain price feed first. If the feed was stale (updated > 2 hours ago), it fell back to a Uniswap V3 spot price query—not TWAP—as a secondary source. The attacker front-ran the Chainlink price update by pausing the oracle feed (not directly, but by exploiting a mallet in the Chainlink aggregator’s minAnswer mechanism—a known issue in low-decimal tokens). By making the feed appear stale, the contract called the fallback function, which read the manipulated spot price.

Vulnerability #2: Redemption Calculation Using Manipulated Price

The redeemUnderlying(uint256 shares) function used getPrice() to compute the value of shares: amountOut = shares price / (10oracleDecimals). When the price was pushed to 0.98 for USDC/DAI (where USDC was the silo token), the contract undervalued the USDC collateral. The attacker deposited a small amount of USDC as collateral (100k USDC), then borrowed DAI against it. Normally, the 150% collateralization ratio would prevent borrowing more than 66k DAI. But with the manipulated price, the contract calculated the collateral value as 100k 0.98 = 98k USDC, allowing a maximum 65k DAI borrow. Not profitable.

The real exploitation came from reentrancy in the liquidation process.

Vulnerability #3: Reentrancy via Liquidation Callback

The liquidate(address borrower, uint256 repayAmount) function transferred the repay tokens to the borrower’s contract before updating the borrower’s debt state. The attacker deployed a contract that, upon receiving tokens, re-entered redeemUnderlying with the same shares—but now with a modified state (the debt was already cleared). The code followed the Checks-Effects-Interactions pattern only partially: it checked the collateralization ratio after the repay, but the state update for the borrower’s debt was delayed. This allowed the attacker to borrow again on the same collateral, inflating the position.

Step-by-Step Transaction Flow

  1. Flash loan 100 million USDC from Aave V3 (no collateral).
  2. Swap 50 million USDC for 50 million DAI on Uniswap V3 (creating the spot price dip).
  3. Wait 10 seconds for the Chainlink USDC/DAI feed to be considered stale (the attacker had earlier triggered a setMinAnswer call on the feed contract via a front-running bot—a known vulnerability in low-everage tokens).
  4. Deposit 100k USDC into Silo USDC-ETH silo as collateral.
  5. Borrow 65k DAI (legitimate, under manipulated price).
  6. Liquidate self—call liquidate with 65k DAI as repayment. The liquidation contract calculates the borrower’s debt as 65k DAI, so repayAmount equals debt. The liquidation sends 65k DAI to the attacker’s contract, decreasing the protocol’s DAI balance. But the borrower’s debt is set to zero after the transfer.
  7. Re-enter redeemUnderlying with the same 100k USDC worth of shares. Since debt is zero, the contract allows full redemption. The price is still manipulated at 0.98, so amountOut = shares * 0.98 / 1e8 (approx 98k USDC). The contract sends 98k USDC to attacker.
  8. Repeat liquidation and redemption in a loop—each iteration extracts 98k USDC minus the 65k DAI repaid (net 33k USDC per loop). After 136 cycles, the team drained 45 million USDC.

Contrarian: What the Bulls Got Right

To be fair, the Silo team did one thing correctly: they forced all borrows to go through a maxBorrow check against the protocol’s liquidity. The attacker could not drain the entire silo in one shot—the loop structure suggests the pull had a limit. Also, the flash loan source (Aave) was not restricted; the team argued that all DeFi protocols must be flash-loan resistant by design. They had also implemented a timelock on oracle parameters, but the fallback path bypassed it.

The bulls would say: “Silo’s isolation design prevented the attack from spreading to other silos—only the USDC-ETH pair was compromised.” That is true. The ETH-USDC silo lost only $600k in a separate test attack. The isolation worked. But isolation is cold comfort when a single silo loses 45 million. The architecture treat the symptom, not the disease.

Takeaway: The Accountability Call

The Silo exploit was not a failure of a single function. It was a systemic failure of defense-in-depth—a stack of individually minor omissions that, when combined, formed a lethal exploit chain. The auditors missed four things:

  1. The stale oracle fallback path should have triggered a pause, not a spot price read.
  2. The liquidate function should have used a reentrancy lock.
  3. The redemption calculation should have used the TWAP, not the live price.
  4. The redeemUnderlying should have recalculated the collateral value after liquidation.

Silence in the logs is louder than the error. The absence of revert messages in the attack transaction means the contract executed exactly as written. The attacker simply read the code and found the exit.

What now? Silo has patched the fallback path, added reentrancy guards, and increased the Chainlink staleness threshold to 30 minutes. But the shadow of this exploit will linger. Every protocol with a similar oracle fallback should audit it today. Flash loans don’t steal; they exploit logic gaps. The ghost in the smart contract state is always the last oversight.

Technical Addendum: Code Fragments and Simulation

For readers who want to verify the attack path independently, I have included the key Solidity snippets from the exploited contracts (anonymized for responsible disclosure).

// Vulnerability 1: Fallback to spot price
function getPrice() public view returns (uint256) {
    (uint80 roundID, int256 price, , uint256 timestamp, uint80 answeredInRound) = chainlinkFeed.latestRoundData();
    if (block.timestamp - timestamp > 2 hours) {
        // Stale fallback
        (uint160 sqrtPriceX96, , , , , , ) = uniswapV3Pool.slot0();
        return sqrtPriceX96; // spot price, not TWAP
    }
    return uint256(price) * (10**10);
}

The correct implementation should use observe() to query the TWAP accumulator over a recent window. Even a 5-minute TWAP would have prevented this manipulation.

Audit Gap Analysis

| Audit Firm | Finding | Missed Vulnerability | Why Missed | |------------|---------|----------------------|------------| | Trail of Bits | Oracle staleness handling adequate | Fallback to spot price not considered | Focused on Chainlink integration, not Uniswap spot price | | ConsenSys Diligence | Reentrancy on liquidation flagged as low risk | Assumed no external calls in liquidation path | Actually had external call to borrower contract | | SlowMist | Price manipulation via flash loans possible | Did not test for combinatorial attacks | Used isolated function testing |

The lesson is clear: audits must model adversarial composability. A single vulnerability is rarely the exploit. It is always the combination.


Tracing the ghost in the smart contract state leads to the same conclusion every time: the code is the truth. Listen to it.

Silence in the logs is louder than the error. The attacker did not break the code. They simply understood it better than the builders.

Flash loans don’t steal. They reveal the gaps in your logic.

Market Prices

Coin Price 24h
BTC Bitcoin
$77,688 -2.44%
ETH Ethereum
$2,437.59 -2.68%
SOL Solana
$103.65 -2.24%
BNB BNB Chain
$689.5 -2.34%
XRP XRP Ledger
$1.39 -2.80%
DOGE Dogecoin
$0.0846 -2.87%
ADA Cardano
$0.2003 -4.30%
AVAX Avalanche
$7.26 -2.37%
DOT Polkadot
$0.8416 -3.84%
LINK Chainlink
$11.33 -3.69%

Fear & Greed

68

Greed

Market Sentiment

Event Calendar

{{年份}}
12
05
halving BCH Halving

Block reward halving event

22
03
unlock Optimism Unlock

Circulating supply increases by about 2%

28
03
unlock Arbitrum Token Unlock

92 million ARB released

18
03
unlock Sui Token Unlock

Team and early investor shares released

10
05
upgrade Ethereum Pectra Upgrade

Raises validator limit and account abstraction

15
04
halving Bitcoin Halving

Block reward reduced to 3.125 BTC

08
04
upgrade Solana Firedancer

Independent validator client goes live on mainnet

30
04
upgrade Celestia Mainnet Upgrade

Improves data availability sampling efficiency

Tools

All →

Altseason Index

40

Bitcoin Season

BTC Dominance Altseason

Gas Tracker

Ethereum 28 Gwei
BNB Chain 3 Gwei
Polygon 42 Gwei
Arbitrum 0.5 Gwei
Optimism 0.3 Gwei

Market Cap

All →
# Coin Price
1
Bitcoin BTC
$77,688
1
Ethereum ETH
$2,437.59
1
Solana SOL
$103.65
1
BNB Chain BNB
$689.5
1
XRP Ledger XRP
$1.39
1
Dogecoin DOGE
$0.0846
1
Cardano ADA
$0.2003
1
Avalanche AVAX
$7.26
1
Polkadot DOT
$0.8416
1
Chainlink LINK
$11.33

🐋 Whale Tracker

🔵
0x9093...1e27
1d ago
Stake
5,725,760 DOGE
🔴
0x6608...f314
12m ago
Out
1,842,448 USDC
🔴
0x71e2...d7b6
5m ago
Out
36,811 SOL

💡 Smart Money

0x4b0e...eaaa
Experienced On-chain Trader
+$3.0M
73%
0x3fa4...60c5
Top DeFi Miner
+$1.7M
67%
0xe8d9...6f48
Early Investor
+$1.6M
89%