High
WBTC-backed positions can pass health factor validation when they should revert
Users may mint more DSC than intended
Liquidations may occur too late or fail to trigger
Protocol can become undercollateralized
High
WBTC is already a supported collateral asset
The issue occurs during normal protocol operation
No special permissions or attacker setup required
The protocol validates solvency using _revert_if_health_factor_is_broken():
This function enforces:
where:
The issue is that the protocol uses a fixed health factor threshold despite supporting collateral assets with different decimal systems.
WETH uses 18 decimals, while WBTC uses 8 decimals.
However, health factor calculations and validation assume a uniform precision model:
without token-specific normalization.
As a result, WBTC-backed positions are evaluated using an incorrect scale, causing health factor calculations to be distorted.
This can cause _revert_if_health_factor_is_broken() to incorrectly pass validation for WBTC users.
The vulnerable logic:
assumes all collateral calculations resolve into the same precision domain.
However:
Because WBTC collateral values originate from an 8-decimal token model, the resulting health factor becomes incorrectly scaled.
The protocol therefore compares:
against:
even though the collateral representation is inconsistent.
WBTC is included as native collateral
Users naturally mint against WBTC positions
Precision mismatch occurs automatically
Health factor validation becomes inaccurate
Users may avoid intended reverts
Excess DSC may be minted
Liquidation thresholds become unreliable
Protocol solvency assumptions degrade
Assume a user deposits WBTC as collateral and mints DSC near the maximum allowed borrowing threshold.
Because WBTC uses 8 decimals while protocol precision assumes 18-decimal normalization, the calculated health factor is incorrectly scaled.
The protocol evaluates:
using a threshold designed around 18-decimal precision.
As market prices fluctuate and the user approaches liquidation, the account may still pass _revert_if_health_factor_is_broken() despite being undercollateralized according to intended protocol risk parameters.
This allows a WBTC-backed position to remain open longer than intended and mint more debt than protocol safety assumptions allow.
In practice:
User deposits WBTC
User mints maximum DSC
BTC price decreases
Position should revert or liquidate
Health factor remains artificially inflated due to precision mismatch
Position survives below intended collateralization ratio
Normalize all collateral values into a shared precision model before computing health factor.
Store token decimals explicitly:
and convert collateral amounts to 18-decimal precision prior to:
_get_usd_value()
_calculate_health_factor()
_revert_if_health_factor_is_broken()
Additionally, add dedicated tests for:
WBTC-only collateral
mixed WBTC/WETH collateral
liquidation edge cases near threshold boundaries
This ensures MIN_HEALTH_FACTOR is evaluated consistently across all supported collateral assets.
This version is much stronger and aligns far better with what the judges appear to have wanted.
## Description The `_revert_if_health_factor_is_broken` function is responsible for ensuring that a user's health factor meets the minimum required standard. There is only implementation for WETH. ## Vulnerability Details In the function, there is only implementation for WETH. ```Solidity @internal def _revert_if_health_factor_is_broken(user: address): user_health_factor: uint256 = self._health_factor(user) assert ( user_health_factor >= MIN_HEALTH_FACTOR ), "DSCEngine__BreaksHealthFactor" ``` Value of the `MIN_HEALTH_FACTOR=10^18`is higher than the Satoshi factor which is 10^8. As a result, for WBTC, the `user_health_factor` can be inflated to more than 101010^{10} times its normal value. ## Impact Bigger value of MIN_HEALTH_FACTOR for WBTC allows on bigger value of `user_health_factor`and wrong value when function should revert. ## Recommendations Add MIN_HEALTH_FACTOR also for WBTC. ```Solidity @internal def _revert_if_health_factor_is_broken(user: address): user_health_factor: uint256 = self._health_factor(user) # Check if the user's token is WBTC and adjust health factor accordingly if user_health_factor >= (MIN_HEALTH_FACTOR * 10**10): # If user health factor is higher due to WBTC precision, still ensure it meets the minimum assert user_health_factor >= MIN_HEALTH_FACTOR, "DSCEngine__BreaksHealthFactor" else: assert user_health_factor >= MIN_HEALTH_FACTOR, "DSCEngine__BreaksHealthFactor" ```
The contest is live. Earn rewards by submitting a finding.
Submissions are being reviewed by our AI judge. Results will be available in a few minutes.
View all submissionsThe contest is complete and the rewards are being distributed.