Sui
October 15, 2025

Typus Finance $3.44M Oracle Manipulation Attack

Typus Finance lost $3.44M through oracle manipulation exploiting missing authorization check in custom oracle module. Attacker manipulated prices to drain TLP pool via arbitrage.

Typus Finance $3.44M Oracle Manipulation Attack

TLDR

On October 15, 2025, Typus Finance on the Sui blockchain suffered a critical oracle manipulation attack resulting in approximately $3.44 million in losses. The attacker exploited a missing authorization check in a custom oracle module to manipulate token prices, draining 588,357.9 SUI, 1,604,034.7 USDC, 0.6 xBTC, and 32.227 suiETH from the TLP liquidity pool contract.

Attack Overview

The Typus Finance exploit was an oracle manipulation attack that took advantage of an access control vulnerability in the project's custom oracle module. The vulnerable contract, deployed on November 13, 2024, was notably excluded from the project's May 2025 audit conducted by MoveBit. The attacker discovered that the update_v2 function in the oracle module lacked a critical assertion check to enforce authorization, allowing any address to manipulate oracle prices despite the presence of a whitelist mechanism.

The attack began at 13:05 UTC when the attacker executed the first malicious transaction. By the time the Typus team was alerted by a community member at 13:24 UTC, the attacker had already initiated the exploit. The team responded swiftly, pausing all smart contracts within 15 minutes at 13:39 UTC, but significant damage had already been done. The attacker subsequently bridged the stolen assets to Ethereum through Circle CCTP, converting them to DAI to obscure the money trail.

Technical Analysis

The vulnerability existed in the typus_oracle/sources/oracle.move module, specifically within the update_v2 function responsible for updating oracle prices. The function accepted an UpdateAuthority capability object as a parameter, which was implemented as a shared object accessible to anyone on the network.

public fun update_v2( oracle: &mut Oracle, update_authority: &UpdateAuthority, price: u64, twap_price: u64, clock: &Clock, ctx: &mut TxContext ) { // check authority vector::contains(&update_authority.authority, &tx_context::sender(ctx)); version_check(oracle); update_(oracle, price, twap_price, clock, ctx); }

The critical flaw was that while the function called vector::contains() to check if the sender's address existed in the authorization whitelist, it failed to assert the result of this check. Without an assert! statement wrapping this verification, the boolean result was simply computed and discarded, effectively bypassing the entire authorization mechanism.

The UpdateAuthority structure was defined as a shared object, making it accessible to any caller:

public struct UpdateAuthority has key { id: UID, authority: vector<address>, } entry fun new_update_authority( _manager_cap: &ManagerCap, ctx: &mut TxContext ) { let update_authority = UpdateAuthority { id: object::new(ctx), authority: vector[tx_context::sender(ctx)] }; transfer::share_object(update_authority); }

The attacker exploited this vulnerability in a three-step process. First, they called update_v2 to manipulate oracle prices for specific token pairs. In the initial transactions, they set the oracle price for one asset to an artificially high value of 651,548,270 while setting another to 1, creating an extreme price disparity that the protocol would accept without question.

With manipulated oracle prices in place, the attacker proceeded to execute arbitrage swaps through the typus_perp/sources/tlp/lp_pool.move contract. The TLP pool's swap mechanism relied entirely on oracle prices rather than implementing a constant product formula or other price discovery mechanism:

let (price_f_token_to_usd, price_f_decimal) = oracle_from_token.get_price_with_interval_ms(clock, 0); let (price_t_token_to_usd, price_t_decimal) = oracle_to_token.get_price_with_interval_ms(clock, 0); let from_amount_usd = math::amount_to_usd( from_amount, f_token_config.liquidity_token_decimal, price_f_token_to_usd, price_f_decimal ); let to_amount_value = math::usd_to_amount( from_amount_usd, t_token_config.liquidity_token_decimal, price_t_token_to_usd, price_t_decimal );

This design meant that the swap function would calculate token exchange amounts purely based on the manipulated oracle values. In one transaction, the attacker swapped merely 1 SUI (with 9 decimal precision) for 60,000,000 XBTC (8 decimal precision, equivalent to approximately 0.6 BTC), representing an absurdly profitable exchange enabled solely by the false oracle prices.

The attacker repeated this pattern across multiple transactions, systematically draining various token pools. According to blockchain analysis, the attacker launched a total of 10 separate oracle manipulation attacks, each time updating prices and immediately executing profitable swaps before the protocol team could respond.

Code Vulnerability

The fix for this vulnerability is straightforward but critical. The missing authorization check should have been implemented as follows:

public fun update_v2( oracle: &mut Oracle, update_authority: &UpdateAuthority, price: u64, twap_price: u64, clock: &Clock, ctx: &mut TxContext ) { // Proper authorization check with assertion assert!( vector::contains(&update_authority.authority, &tx_context::sender(ctx)), E_UNAUTHORIZED ); version_check(oracle); update_(oracle, price, twap_price, clock, ctx); }

Interestingly, the Typus codebase contained a secure implementation of capability-based access control in other parts of the oracle module. The update function demonstrated the correct pattern:

public fun update( oracle: &mut Oracle, _manager_cap: &ManagerCap, price: u64, twap_price: u64, clock: &Clock, ctx: &mut TxContext ) { version_check(oracle); update_(oracle, price, twap_price, clock, ctx); }

In this secure implementation, the ManagerCap capability object was transferred to a specific owner during initialization using transfer::transfer(), creating an address-owned object that only the administrator could access. This demonstrates that the development team understood proper access control patterns but failed to consistently apply them across all sensitive functions.

Impact Assessment

The attack resulted in direct losses of approximately $3.44 million from the TLP contract, consisting of 588,357.9 SUI, 1,604,034.7 USDC, 0.6 xBTC, and 32.227 suiETH. The exploit was isolated to the TLP liquidity pool contract, while other Typus products remained secure.

Notably, the SAFU and DeFi Options Vaults were not affected by the attack. These products employed an independent verification mechanism through automated cranker wallets that performed mandatory price validation against a separate, correctly functioning oracle before executing any transactions. When the manipulated prices reached these systems, the verification process rejected them, successfully neutralizing the threat to these vault products.

User collateral held in open positions also remained secure, as these funds were stored in separate contracts with no direct dependency on the compromised TLP contract. However, liquidity providers in the TLP pool suffered the full impact of the losses as their pooled funds were drained through the manipulated swaps.

Following the attack, the stolen funds were moved through a complex laundering operation. The attacker first swapped suiETH, xBTC, and most SUI tokens for USDC using Sui-based DEXes including Cetus, Haedal Protocol, and Turbos. They then bridged approximately 3,430,717 USDC to Ethereum through Circle CCTP across 14 separate transactions, sending the funds to address 0xeb8a15d28dd54231e7e950f5720bc3d7af77b443. On Ethereum, the funds were swapped to 3,430,241.91 DAI via Curve and transferred to a new address 0x4502cf2bc9c8743e63cbb9bbde0011989eed03c1, where they remained at the time of reporting.

The attacker's initial funding came from privacy-enhanced sources, with the Ethereum address receiving 0.041 ETH that originated from Tornado Cash on the BSC network. This suggests a sophisticated operation with pre-planned obfuscation measures.

Response and Recovery

Upon detection of the exploit at 13:24 UTC, the Typus Finance team executed an emergency response protocol. All smart contracts were paused within 15 minutes at 13:39 UTC to prevent further exploitation. By 13:42 UTC, the team had identified the root cause of the vulnerability. They formally reported the incident to the Sui Foundation at 13:48 UTC and filed reports with law enforcement authorities by 14:54 UTC.

The team engaged multiple security partners to assist with the investigation and fund tracing efforts. As of time of writing, the team was discussing an asset recovery plan for affected TLP liquidity providers, though specific details have not yet been announced.

As part of the remediation process, Typus Finance committed to deploying new, fully audited smart contracts to replace the vulnerable versions. The team emphasized their commitment to conducting comprehensive security audits of all contract code before future deployments, including previously unaudited modules like the custom oracle that enabled this attack.

In an attempt to recover the stolen funds, Typus Finance sent an onchain message to the attacker's Ethereum address offering a white hat bounty. The message, sent via transaction 0x8755eaf8704bfb190d4879c7772a1a0edd81c29eb66bd35ca5e3303fa802536a, offered a 15% white hat bounty in exchange for the return of the remaining 85% of funds, with a commitment not to pursue further legal action upon return. The team provided contact information at [email protected] for the attacker to initiate negotiations.

Be Among The First to Know

In DeFi, a small delay costs millions. Get the threat intelligence to rely on.

© 2025 Defimon by Decurity

Powered by QuickNode