The function _revert_if_health_factor_is_broken is intended to halt execution whenever a user’s health factor falls below the required minimum. However, due to a scaling mismatch between assets with different decimals - specifically WBTC (8 decimals) versus WETH (18 decimals) - the computed user_health_factor for WBTC positions can be inflated by ~10^10. Because MIN_HEALTH_FACTOR is set to 1e18, the bug may allow under‑collateralized WBTC positions to avoid reverting, undermining liquidation safety checks.
The _revert_if_health_factor_is_broken function ensures that a user's health factor remains above the required minimum threshold.
Because MIN_HEALTH_FACTOR is set to 10^18 - ten orders of magnitude greater than Bitcoin’s Satoshi precision of 10^8 - the user_health_factor for WBTC can become inflated by a factor exceeding 10^10 relative to its true value.
Likelihood: High
WBTC deposits are common, and the code path is generic. Any user holding WBTC may hit the faulty branch where WETH scaling/parameters are implicitly applied.
Unit mismatches of this kind usually escape simple tests unless there are explicit multi‑decimal invariant tests.
Impact: High
Broken safety checks: Under‑collateralized (unsafe) WBTC positions do not revert in places that depend on _revert_if_health_factor_is_broken, allowing bad debt and bypassing liquidation guards.
Protocol insolvency risk: Persistently overstated health factors can allow excessive borrowing, impairing the system’s solvency during price moves.
Goal: Show that a user with an actually unsafe WBTC position (HF < 1.0) still passes the _revert_if_health_factor_is_broken check because the computed HF is inflated by ~10^10.
Normalize all token amounts to 18 decimals before any risk calculations:
Compute scale_up = 10^(18 − token.decimals) for each asset.
Convert raw amounts: amount_1e18 = amount_raw * scale_up.
Ensure all prices and thresholds are applied in a consistent fixed‑point (preferably 1e18).
Never mix per‑asset parameters:
Use the WBTC liquidation threshold/collateral factor for WBTC positions, not WETH’s.
Centralize parameter lookup by token address to avoid cross‑asset leakage.
Strengthen tests:
Unit tests for 8‑decimals (WBTC, USDC/USDT) and 18‑decimals (WETH, DAI) assets.
Property/invariant tests: assert that lowering collateral or raising debt can only decrease HF and eventually fail the check.
Differential tests comparing correct vs. buggy implementations on randomized inputs.
Runtime assertions / monitoring:
Add a sanity check: if an asset’s decimals ≠ 18, assert that a normalization step has been applied.
Telemetry/metrics for extreme HF values to detect abnormal inflation.
## 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.