Full Report
Sherlock is a blockchain auditing platform in the form of contests. They had a staking pool setup with Euler. The function balanceOf on the EulerStrategy.sol is used to determine the current value held by the EulerStrategy. This result is then used to calculate the price per share of the user's withdrawing position. The function balanceOf calls EUSDC.balanceOfUnderlying() underneath it. The problem with this is that the actual value being returned may be manipulated. Although the contract believes this will be an atomic call (no other paths ran), this is NOT the case. Specifically, the totalAssets is updated prior to the call but the totalBalances is NOT updated yet. This results in computeExchangeRate() being higher than the actual value. An attacker could use this to change the price and obtain more money than anticipated. This attack is only possible because arbitrary calls from 1inch can be made while swapping. To manipulate the pool, an attacker needs to transfer a large amount of USDC to Euler, inflating the price of computeExchangeRate. Since the price per share is higher, an attacker can redeem more USDC than they should be able to. In the proof of concept, the author has to setup the stage for the swaps and stake money. In Foundry, it is possible to fast forward the chain to a different time in order to allow this POC to be possible. Neat! Once they have performed the swap, they setup the callback on 1inch. With the setup done, we can make the call. The callback is hit on the withdraw. Upon hitting the callback, USDC is transferred to Euler while in the callback of 1inch. This cross-protocol reentrancy creates a manipulated exchange rate. At this point, we exit the position, collect our winnings and repay the flash loan. To fix this vulnerability, a reentrancy lock was added in Euler. This bug was missed by Trail of Bits for Sherlock but found during an audit of Euler. However, it was only noted as a medium severity finding and never fixed as a result. Overall, an interesting article for a crazy cross protocol reentrancy. The POC is very well explained as well.
Analysis Summary
# Vulnerability: Manipulated Exchange Rate via Cross-Protocol Reentrancy in EulerStrategy
## CVE Details
- **CVE ID**: N/A (Project-specific discovery; no CVE assigned)
- **CVSS Score**: Not officially rated (Estimated: 8.6 High - `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:N/I:H/A:N`)
- **CWE**: CWE-841: Improper Enforcement of Behavioral Workflow, CWE-799: Improper Control of Interaction Frequency (Reentrancy)
## Affected Systems
- **Products**: Sherlock Staking Pools / EulerStrategy
- **Versions**: Legacy `EulerStrategy.sol` prior to July 2022 patch
- **Configurations**: Any yield strategy relying on `EUSDC.balanceOfUnderlying()` during atomic swap operations (specifically via 1inch or similar aggregators allowing arbitrary callbacks).
## Vulnerability Description
The vulnerability is a **cross-protocol reentrancy** flaw. The `EulerStrategy.sol` contract uses the `balanceOf` function to determine the value of assets held in Euler Finance to calculate the "price per share" during user withdrawals.
The underlying problem exists in the Euler Finance `computeExchangeRate()` logic. When assets are transferred into Euler, the `totalAssets` value is updated before the `totalBalances`. If an attacker triggers a withdrawal and uses an arbitrary call (via a 1inch swap callback) to inject USDC into Euler mid-transaction, the `balanceOfUnderlying()` returns a manipulated, inflated value. Because the price per share is derived from this inflated value, the caller can redeem significantly more underlying assets than they are entitled to.
## Exploitation
- **Status**: PoC available (Reported via Immunefi bug bounty)
- **Complexity**: High (Requires orchestrating flash loans, 1inch callbacks, and precise timing)
- **Attack Vector**: Network
## Impact
- **Confidentiality**: None
- **Integrity**: High (Direct theft of funds through manipulated asset redemption)
- **Availability**: None
## Remediation
### Patches
- **Euler Finance**: Implemented a global reentrancy lock to prevent state manipulation during atomic calls.
- **Sherlock**: Updated `EulerStrategy` to mitigate reliance on the manipulated exchange rate oracle and integrated the Euler fix.
### Workarounds
- Implement "Slippage limits" on withdrawals that prevent exiting a position if the price per share deviates beyond a specific threshold in a single block.
- Disable or whitelist specific external calls/callbacks within the transaction flow of sensitive financial functions.
## Detection
- **Indicators of Compromise**: Large flash loan activity involving USDC followed by immediate interactions with Sherlock staking pools and 1inch protocol in a single transaction.
- **Detection Methods**: Monitor for discrepancies between `totalAssets` and `totalBalances` within Euler's core contracts during transaction execution (Runtime Verification).
## References
- **Sherlock Post-Mortem**: hxxps://paragraph[.]com/@sherlock/sherlock-yield-strategy-bug-bounty-post-mortem
- **Euler Finance Audit**: Referenced as a "Medium" severity finding in prior Trail of Bits/Euler audits.
- **Immunefi**: hxxps://immunefi[.]com/ (Platform where the bug was reported).