Full Report
Jet Protocol was a lending and borrowing protocol built on Solana. The function _market_value() is used to determine the total market value of the loans that had been taken out. So, if this function was broken in some way, you would be able to bypass the protection to take out arbitrary loans. Recently, the protocol had implemented the capability to close a Solana account. Upon doing this, the account is set back to the Pubkey::default value and gives back some of the rent costs. However, the collateral to loan ratio using the function _market_value() has a fatal control flow flaw with this new functionality. It is using Pubkey::default as the indicator to exit the list. So, if an account is closed then this function is interacted with, the loop will exit early! Overall, a fairly simple issue of default values leads to a complete rug pull. To me, the verification of a default value is a red flag and should try to be avoided of things like this. Good find!
Analysis Summary
# Vulnerability: Jet Protocol Total Market Value Calculation Bypass
## CVE Details
- **CVE ID**: N/A (Discovered via Bug Bounty/Immunefi)
- **CVSS Score**: 9.1 - 10.0 (Critical estimate)
- **CWE**: CWE-670: Always-Incorrect Control Flow Implementation
## Affected Systems
- **Products**: Jet Protocol (Solana-based lending/borrowing program)
- **Versions**: Mainnet versions following the upgrade that added account closure features (prior to January 2022 fix).
- **Configurations**: Systems where `close_loan_account` or `close_collateral_account` instructions are enabled.
## Vulnerability Description
The vulnerability stems from a control flow flaw in the `_market_value` and `is_healthy` functions. These functions calculate a user's total collateral and loan debt by iterating through a list of account positions.
The logic utilized `Pubkey::default()` as a sentinel value to indicate the end of the list, assuming all active positions would be non-default and contiguous. However, a recent update introduced the ability to close accounts to recover rent. When an account was closed, the program set the specific position's address to `Pubkey::default()`.
If a user closed a loan or collateral account that was not at the very end of their list, the `break` and `take_while` statements in the iteration logic would trigger prematurely. This caused the protocol to ignore all valid assets or debts positioned after the "closed" (default) entry in the array.
## Exploitation
- **Status**: PoC discovered and reported via Immunefi; patched before malicious exploitation.
- **Complexity**: Low
- **Attack Vector**: Network (Smart Contract Interaction)
## Impact
- **Confidentiality**: None
- **Integrity**: High (Can manipulate loan-to-collateral records)
- **Availability**: High (Potential drain of all Protocol TVL/Rug pull scenario)
## Remediation
### Patches
- Jet Protocol deployed a fix to mainnet in early January 2022. The fix involved modifying the iteration logic to ensure the loop does not terminate early when encountering a default public key if subsequent positions may still be valid.
### Workarounds
- Users were advised to interact with the protocol via the updated UI/CLI that implements the correctly patched instruction sets.
## Detection
- **Indicators of Compromise**: Multiple `close_loan_account` calls followed by massive borrowing transactions that exceed standard collateral ratios.
- **Detection Methods**: On-chain monitoring of the `is_healthy` check results compared to actual account balances; auditing the `obligation.rs` state for `Pubkey::default()` values in non-terminal array positions.
## References
- Jet Protocol GitHub Archive: hxxps://github[.]com/jet-lab/jet-v1/blob/e9cfe1810a6614b78934704ac46dffef67a8d794/programs/jet/src/state/obligation.rs#L293
- Immunefi Bug Bounty: hxxps://immunefi[.]com/bounty/jetprotocol/
- Original Report: hxxps://medium[.]com/@0xjayne/how-to-freely-borrow-all-the-tvl-from-the-jet-protocol-25d40e35920e