Full Report
Gains is a leverage-trading platform. In particular, users can provide small amount of funds yet still gain high exposure to a given asset. The leverage portion allows for gains or losses of multiple times. There are two special types of orders: stop loss and take profit. Stop loss will remove the current position after an X% decrease in price while the take profit will cash out once a specific price point has been hit. On Gains, regardless if it's a long or short, there are three types of orders: Market: Open a trade immediately. Limit: Go long on a lower price than present or reversed for short. Stop Limit: Go long on a higher price than present or reversed for short. The trade struct has several fields, including tp for take-profit and sl for stop loss profit. If the price was 1K with a 5x leverage and the SL was 900 with a price below that, then the return would be -50. All of this is standard to the protocol. In the function that does the calculations above, there is some logic for figuring out payouts which deals with negative numbers. If the field t.openPrice is t.sl, then the current pricing model breaks. As a result, if the token drops on a long then we'd gain unintended profit. By setting up parameters for the trade in a very specific way, including specific order types, it was possible to trigger this condition. After finding this bug they kept looking and found another one! The function _currentPercentProfit casts currentPrice (which is included by end users) from an unsigned integer to a signed integer. By specifying the price to be extremely large, it would underflow to a negative value! Since we're dealing with shorts and longs, it was After doing both of these tricks, the position could be immediately closed for a 900% profit. Crazily enough, the profit didn't depend on the movement of the token because of the confusion between the different types. To fix both of the bugs, an invariant check no sl/tp to be within the proper bounds was done. I'm hopeful they introduced more patches than just invariant checks but invariant checks are amazing for killing exploit paths like this one. With my inexperience with leveraged trading and the Gains network logic, I found the first bug to understand. However, it seems like it was just a logic flaw that broke an invariant of the protocol. To me, it was interesting to see can we make the value greater than this other value because it would be bad which led them to the bugs in the end. Good finds!
Analysis Summary
# Vulnerability: Logic Flaws Leading to Unintended Profit in Gains Network Forks
## CVE Details
- CVE ID: **Not specified in the source material.** (Multiple independent issues described)
- CVSS Score: **Critical/High** (Based on 900% profit potential and fund loss risk, but no formal score provided.)
- CWE: **CWE-190** (Integer Overflow or Wraparound - for Issue 2), **CWE-824** (Unreachable Code/Logic Error - for Issue 1)
## Affected Systems
- Products: **Forks of Gains Network** (Specific forks mentioned include Gambit Trade, Holdstation Exchange, and Krav Trade, all possibly using vulnerable previous versions).
- Versions: **Previous versions of Gains Network contracts** used by these forks. The current version of Gains Network is stated to not contain these issues.
- Configurations: Trades configured with specific order types and parameters to trigger the invariant break/underflow conditions.
## Vulnerability Description
Two distinct critical vulnerabilities were identified, allowing users to immediately close positions for a guaranteed, massive, and unintended profit (up to 900%), independent of market movement.
**Issue 1: Stop Loss (SL) set equal to or breaking an Invariant related to `openPrice`**
When calculating payouts in the function handling profit/loss, if the trade's stop loss price (`t.sl`) was set to equal the `t.openPrice`, the established pricing model broke. This specific configuration, achievable via precise order parameter setting, resulted in an unintended profit calculation when the token price dropped for a long position. This seems to stem from a broken protocol invariant.
**Issue 2: Unsafe Casting of Price Data**
The function `_currentPercentProfit` unsafely casts the `currentPrice` (received as an unsigned integer from end-users) to a signed integer. By supplying an extremely large unsigned price value during trade execution, this value undergoes integer underflow when cast to a signed integer, resulting in a negative value. This misinterpretation, combined with the first issue's logic exploits, allowed for the immediate closing of positions for a 900% profit.
## Exploitation
- Status: **PoC available** (Implicitly, as the researchers were able to demonstrate the 900% profit trigger through specific trade setups).
- Complexity: **Medium** (Requires specific knowledge of the protocol logic, order types, and how to manipulate price inputs/SL/TP settings).
- Attack Vector: **Network** (Interaction via smart contract calls).
## Impact
- Confidentiality: **None** (Financial reporting failure)
- Integrity: **High** (Allows users to extract funds fraudulently, directly impacting the liquidity pool's integrity/balance).
- Availability: **Low** (Protocol still functions, but funds are at risk of drain).
## Remediation
### Patches
- The core fix involved introducing **invariant checks** in the backend logic to ensure that `sl` and `tp` values remain within proper, logical bounds relative to the trade parameters (e.g., `sl` cannot be set in a way that breaks the profit calculation model). (The article does not list specific version numbers for patched forks).
### Workarounds
- **Immediate Action for Forks:** Projects running Forks of Gains Network using older versions must immediately patch their contract logic, specifically ensuring that price calculations involving unsigned/signed conversions are safe (Issue 2) and that stop-loss/take-profit logic does not allow for situations where `t.sl == t.openPrice` during payout calculations (Issue 1).
- **Monitoring:** Strictly monitor large, immediate closure transactions following specific trade setups.
## Detection
- **Indicators of Compromise:** Monitoring for closed trades that result in extraordinarily high profit percentages (e.g., 900%) without corresponding significant market movement, particularly those involving trades opened near a specified stop-loss price.
- **Detection Methods and Tools:** Auditing smart contract execution traces for unusual integer casting operations involving price inputs, and verifying that stop-loss and take-profit parameters adhere to expected bounds checks *before* calculations occur.
## References
- Vendor Advisories: Zellic Security Advisory (April 19, 2024).
- Relevant Links:
- hxxps://www.zellic.io/blog/issues-in-forks-of-gains