DEMO — Historical Analysis of Euler Finance
Threat Intelligence Report — Euler Finance
This demo shows our analysis of Euler Finance. Our platform detected all primitives and the compound attack chain before the exploit occurred. Everything you see below is what a subscribed client receives — full contract names, complete finding details, and validated proofs of concept.
Compound multi-step attack paths identified and validated with working PoCs.
Threat Topology
Click any contract card to view its functions, findings, and risk details.
Compound Attack Chain
All primitives chained in a single atomic transaction.
Findings
(10 total)EToken.mint() allows repeated self-minting without collateral ratio enforcement per-operation. An attacker can loop mint calls within a single transaction to inflate eToken balance far beyond deposited collateral, creating unbounded synthetic leverage.
EToken.donateToReserves() destroys the caller’s eToken balance without reducing their debt position. After inflating eTokens via BH-EU-001, the attacker donates them to push the pool into insolvency, making their remaining position eligible for self-liquidation at a discount.
The liquidation module allows a violator to be liquidated by any account, including the violator themselves via a secondary address. Combined with the artificially insolvent position from BH-EU-002, the attacker self-liquidates at the protocol’s liquidation discount, extracting the remaining pool assets.
Aave V2 flash loans provide the initial capital (30M DAI) needed to bootstrap the attack without upfront cost. The borrowed capital seeds the mint loop, and the full attack chain (mint → donate → liquidate) completes within a single atomic transaction before the flash loan must be repaid.
dispatch() routes calls via delegatecall without cross-module reentrancy protection. While individual modules may have guards, there's no unified lock preventing re-entry across module boundaries.
callInternalModule() performs delegatecall to module implementations. While trustedSenders validation exists, the delegatecall shares storage context across all modules.
_createProxy() validates module IDs but the proxy creation pattern is standard and well-tested.
EVault.initialize() accepts a maxLiquidationDiscount parameter that, when set to zero, permanently disables liquidation incentives. Since initialize() is called once at vault deployment and cannot be re-invoked, any vault deployed with this parameter set to zero can never be liquidated, creating a permanent insolvency path.
EulerSavingsRate.gulp() re-smears accrued interest over a new distribution window each time it is called. An attacker can call gulp() repeatedly to reset the distribution schedule, concentrating or diluting interest payments. This enables front-running of large deposits to capture disproportionate yield.
EulerEarn.previewRedeem() uses ceiling division while the actual redeem() path uses floor division. This mismatch causes integrators relying on previewRedeem() to set incorrect approval amounts, permanently bricking withdrawal flows for contracts that pre-approve based on the preview result.
Engagement Tiers
Choose the depth of intelligence and response cadence that matches your protocol's risk profile.
Sentinel
Vanguard
Ready to see what we find on your protocol?
Our findings include full vulnerability reports, working proofs-of-concept on mainnet forks, and detailed remediation guidance. Everything above is exactly what you get.