Full Report
Notional is a lending and borrowing platform on Ethereum. Most operations for their platform are performed using their fCash token. These tokens are redeemable for positive or negative cash flow at a later date, acting as a receipt/IOU. The fCash token is also denoted in its underlying token, such as DAI or USDC. Once settled, it is given out in cToken (collateral tokens, such as cUSDC), which can be redeemed for the original token. All users have a portfolio. This is an array of assets, which is governance limited. There is also an additional asset bitmap portfolio that is very handy for market makers. The name is bitmap, so I assume that the data is a literal bitmap. A user can only hold data in only of these data structures at a time though. While switching from one bitmap to another, there is validation in place. Bitmap Enabled: Validate no assets are currently set in the bitmap. Bitmap Disabled: Require there are no assets in the array from the first mode of operation. Call the function setActiveCurrency. This ensuring that there is no double counting of the current collateral. The bitmap currency is used to keep track of the current currencies being used by the account. This appears to be important for bookkeeping on how much a user has. These currencies can only be changed if there are no debts or credits in the bitmap asset. The call to setActiveCurrency() in the else clause even has a comment about "... so there is no double counting during FreeCollateral.". However, this function is ONLY called during the else clause and NOT the IF statement. As a result, the activeCurrencies field is NOT cleared. By calling external code that sets another currency, such as depositUnderlyingToken(), setActiveCurrency will be called for the account. To get two currencies to be active, we can call enableBitmapForAccoutn with a currency we do not care about then make a second call to enableBitmapForAccoutn after the deposit mentioned. Due to the logic error, the free collateral calcuations will run twice on the asset deposited: once for the bitmap and once for the activeCurrencies. What does free collateral mean in this context though? To evaluate the position of the user, the debts are significantly over collateralized. To denote this, Notional uses free collateral to denominate the ETH that an account holds beyond what it needs to meet the minimum collateral requirements. If positive, the position is proper. If negative, it's eligible for liquidation. If the amount of free collateral is doubled (with the bug above), an attacker could borrow more without actually holding enough of the currency. This means they can trade a small amount of one token and take a loan out for more with the protocol, making it possible to just never pay back the loan to make a profit! To exploit the bug, the steps needs to be taken: Enable the bitmap portfolio for any currency. Deposit funds using depositUnderlyingToken() on the currency you want to double. Enable the bitmap currency again. This performs the double count operation, making it believe we put in more collateral than we actually did. Transfer out the fCash. This will be worth more than our original collateral. Convert fCash into another token and make the money!
Analysis Summary
# Vulnerability: Double Counting of Free Collateral due to Logic Error in Portfolio Switching
## CVE Details
- CVE ID: Not explicitly assigned/provided in the text.
- CVSS Score: Critical (Implied, based on the context of draining liquidity, typical classification for such high-impact DeFi flaws; the text states it was given a severity of "critical").
- CWE: CWE-823 (Incorrect Expiration of Data or Resources) or CWE-754 (Improper Restriction of Operations Within the Bounds of File System Abstraction) could potentially apply, though the core issue is a logic flaw leading to state misrepresentation.
## Affected Systems
- Products: Notional V2 contracts.
- Versions: The specific version containing the vulnerability is not explicitly stated, but it was present prior to remediation/upgrade.
- Configurations: Accounts utilizing the "Asset Bitmap Portfolio" feature where portfolio switching logic is engaged.
## Vulnerability Description
The vulnerability exists in the state management logic surrounding the "Asset Bitmap Portfolio." When switching between the standard array-based portfolio and the bitmap portfolio, the `setActiveCurrency()` function is correctly called in the `else` clause (when disabling the bitmap or switching context) to clear the `activeCurrencies` field, preventing double counting of collateral/debts during FreeCollateral calculation.
However, this cleanup call is **skipped** in the `if` clause (when enabling or interacting with the bitmap portfolio). Because `activeCurrencies` is not cleared, an attacker can trigger the state change mechanism sequentially:
1. Enable the bitmap portfolio for an arbitrary currency.
2. Deposit funds using `depositUnderlyingToken()`, which internally calls `setActiveCurrency()`, setting the deposited asset as active in the `activeCurrencies` field (since the cleanup was skipped).
3. Re-enable the bitmap portfolio for the same or another relevant currency.
This sequence causes the Free Collateral calculation mechanism to count the deposited asset twice—once via the bitmap structure and once via the `activeCurrencies` field—effectively doubling the user's reported collateral. This inflated collateral value allows the attacker to borrow significantly more fCash than they are entitled to based on their actual holdings.
## Exploitation
- Status: **PoC available**. A runnable Proof of Concept (PoC) was prepared using `brownie` scripts on a mainnet fork, demonstrating the attack.
- Complexity: **Medium** (Requires specific sequence of state changes involving portfolio configuration and deposits).
- Attack Vector: **Contract Interaction (Network)**.
## Impact
- Confidentiality: No direct impact mentioned.
- Integrity: **High**. Allows the attacker to fraudulently increase their collateral representation, leading to over-borrowing and depletion of protocol liquidity.
- Availability: **High**. The successful exploit could lead to draining almost all liquidity from the affected markets (e.g., the example showed draining 26.2 million DAI).
## Remediation
### Patches
- The Notional team confirmed the bug and upgraded the affected contracts to remove the vulnerable feature path, followed by a proper fix to reenable the intended functionality. (Specific patched contract versions are not detailed in the summary).
### Workarounds
- No specific external workarounds are detailed, as the vulnerability was addressed directly via contract upgrade by the development team.
## Detection
- **Indicators of Compromise (IoCs):** Sudden, large-scale withdrawals of underlying assets preceded by controlled deposits and unusual sequences of portfolio enablement calls (`enableBitmapForAccount`). Transactions showing collateral calculations resulting in significantly overestimated Free Collateral for specific accounts.
- **Detection Methods and Tools:** Logic anomaly detection in DeFi security monitoring tools focusing on divergences between deposited value and reported collateralization ratios immediately following state-changing operations related to portfolio configuration.
## References
- Vendor advisories: Notional V2 Bugfix Review (Implied via Immunefi report).
- Relevant links - defanged:
- hxxps://medium.com/immunefi/notional-double-counting-free-collateral-bugfix-review-da9304a1238f