Nemo Protocol: Move Language Economic Logic Failure ($2.4M)
On September 8, 2025, Nemo Protocol, a decentralized finance platform built on the Sui blockchain using the Move programming language, was exploited for approximately $2.4 million. The attacker bridged stolen USDC via Circle from Arbitrum to Ethereum following the exploit, demonstrating a cross-chain attack pattern. Notably, this exploit occurred despite Move's safety features designed to prevent common smart contract vulnerabilities.
Technical Overview
The Sui blockchain and its Move programming language were designed with security as a primary consideration. Move's type system, resource ownership model, and formal verification capabilities position it as a safer alternative to Solidity for smart contract development. However, the Nemo Protocol exploit demonstrates that language-level safety does not protect against economic logic errors.
Move Language Safety Features
Move was designed to address common smart contract vulnerabilities:
Move Security Features:
├── Linear type system (prevents double-spending)
├── Resource ownership model (prevents unauthorized copying)
├── Formal verification capabilities
├── Built-in overflow protection
├── Strong type safety
└── Module-based access control
What Move PREVENTS:
├── Integer overflow/underflow (in most cases)
├── Reentrancy attacks (resource model)
├── Unchecked external calls (capability model)
├── Uninitialized variables
└── Type confusion (within module)
What Move DOESN'T PREVENT:
├── Economic logic errors
├── Access control design flaws
├── Oracle manipulation
├── Price feed vulnerabilities
├── Business logic flaws
└── Protocol-level design errors
The Nemo Protocol Context
Nemo Protocol was a lending and borrowing platform on Sui, allowing users to deposit assets as collateral and borrow other assets against them. The protocol implemented standard DeFi lending mechanics:
Nemo Protocol Core Mechanics:
├── Collateral deposits ( assetmultiple types)
├── Borrow against collateral (LTV-based)
├── Liquidation mechanism
├── Interest rate model
├── Oracle price feeds
└── Cross-chain bridge integration
Exploit Analysis
Attack Vector
The specific vulnerability in Nemo Protocol's economic logic allowed the attacker to manipulate the protocol's accounting to extract more value than should have been possible:
Hypothesized Attack Pattern:
// VULNERABLE: Move module with economic logic flaw
module nemo_protocol::lending {
use sui::balance::{Self, Balance};
use sui::coin::{Self, Coin};
use sui::object::{Self, UID};
use sui::transfer;
use sui::tx_context::{Self, TxContext};
// VULNERABILITY: Incorrect collateral value calculation
struct LendingPool<phantom T> has store {
collateral: Balance<T>,
debt: Balance<USDC>,
collateral_value: u64,
debt_value: u64,
}
// VULNERABILITY: Price calculation allows manipulation
public fun borrow<T>(
pool: &mut LendingPool<T>,
amount: u64,
ctx: &TxContext
) {
// Get collateral value
let collateral_usd = calculate_collateral_value<T>(pool);
// VULNERABILITY: No check for minimum health factor
// or health factor calculation error
// Incorrect borrow limit calculation
let max_borrow = collateral_usd * 80 / 100; // 80% LTV
// VULNERABILITY: Price feed manipulation allows
// collateral value inflation
// Borrow amount check is flawed
require!(amount <= max_borrow, EInsufficientCollateral);
// Extract debt
let debt = pool.debt.borrow_mut(amount);
let borrowed_coins = coin::from_balance(debt, ctx);
transfer::public_transfer(borrowed_coins, tx_context::sender(ctx));
}
// VULNERABILITY: Manipulable price calculation
fun calculate_collateral_value<T>(pool: &LendingPool<T>): u64 {
// Price obtained from potentially manipulable oracle
let price = get_price<T>(); // Can be manipulated
// Incorrect value calculation
let value = pool.collateral.value() * price / SCALING_FACTOR;
return value
}
}
Cross-Chain Asset Movement
The exploit demonstrated sophisticated cross-chain attack execution:
Attack Flow:
├── Step 1: Identify Nemo vulnerability
├── Step 2: Execute exploit on Sui (drain position)
├── Step 3: Bridge USDC to Arbitrum via Circle
├── Step 4: Bridge USDC to Ethereum via Circle
├── Step 5: Mix through DEXs to obscure trail
└── Step 6: Final destination (typically Tornado Cash or mixer)
Technical Deep Dive
Economic Logic Vulnerability:
// VULNERABLE: Simplified lending logic
module nemo_protocol::exploit_simulation {
// The core vulnerability was in health factor calculation
// allowing under-collateralized positions
struct Position has key, store {
id: UID,
collateral: u64,
debt: u64,
collateral_type: u8,
}
// VULNERABLE: Incorrect health factor calculation
public fun calculate_health_factor(
collateral: u64,
collateral_price: u64,
debt: u64,
debt_price: u64
): u64 {
// Incorrect formula allows health factor to be
// artificially inflated
let collateral_value = collateral * collateral_price;
let debt_value = debt * debt_price;
// VULNERABILITY: Division order error
// Should be: (collateral_value * 100) / debt_value
// Actual: collateral_value / (debt_value * 100)
let health_factor = collateral_value / (debt_value * 100);
return health_factor
}
// VULNERABILITY: Liquidation threshold bypass
public fun can_liquidate(position: &Position): bool {
let health = calculate_health_factor(
position.collateral,
get_price(position.collateral_type),
position.debt,
get_price(USDC)
);
// VULNERABILITY: Threshold check inverted
// Should be: health < LIQUIDATION_THRESHOLD
// Actual: health > LIQUIDATION_THRESHOLD (always true)
return health > LIQUIDATION_THRESHOLD; // WRONG
}
}
Root Cause Analysis
Primary Vulnerability: Economic Logic Error
The core issue was not a language-level bug but a fundamental error in how the protocol calculated and validated economic invariants:
Economic Invariants Violated:
├── Health factor calculation incorrect
├── Liquidation threshold check inverted
├── Collateral value calculation manipulable
├── Borrow limit computation flawed
└── No oracle manipulation protection
Why Move Didn't Help
Move's safety features target a specific class of vulnerabilities:
| Vulnerability Class | Move Protection | Nemo Vulnerability |
|---|---|---|
| Double-spending | ✓ Prevents | ✗ Not applicable |
| Reentrancy | ✓ Prevents | ✗ Not applicable |
| Integer overflow | ✓ Prevents | ✗ Not applicable |
| Unchecked external calls | ✓ Limits | ✗ Not applicable |
| Economic logic error | ✗ No protection | ✓ Root cause |
Contributing Factors
-
Testing Gaps:
- Economic invariant tests missing
- No adversarial scenario testing
- Oracle manipulation scenarios not tested
-
Audit Scope Limitations:
- Traditional audits focus on code safety
- Economic logic review often superficial
- Cross-chain attack vectors not analyzed
-
Cross-Chain Complexity:
- Multi-chain deployment increased attack surface
- Bridge integration created additional vulnerabilities
- No unified security model across chains
Comparative Analysis: EVM vs Move Security
Traditional EVM Vulnerabilities
Common EVM Attack Vectors:
├── Reentrancy (The DAO style)
├── Access control bypass
├── Integer overflow (pre-Solidity 0.8)
├── Flash loan manipulation
├── Oracle manipulation
├── Front-running
└── Upgrade proxy vulnerabilities
Move ELIMINATES:
├── Reentrancy (resource model)
├── Most access control bugs
├── Integer overflow
├── Unchecked calls
└── Many memory safety issues
Move-Specific Attack Surface
Unique Move Attack Vectors:
├── Economic logic errors (NOT prevented by type system)
├── Capability delegation mistakes
├── Hot potato pattern misuse
├── Cross-module interaction bugs
├── Formal verification scope limitations
└── Cross-chain bridge vulnerabilities
Move DOESN'T PREVENT:
├── Protocol design flaws
├── Business logic errors
├── Oracle integration mistakes
├── Economic invariant violations
└── Social engineering / key management
Cross-Chain Security Comparison
| Aspect | EVM (DeFi) | Move (Sui/Aptos) |
|---|---|---|
| Language safety | Moderate | High |
| Economic logic review | Required | Required |
| Cross-chain attack surface | High | High |
| Bridge security | Critical | Critical |
| Oracle manipulation risk | Same | Same |
Mitigation Strategies
For Move-Based Protocols
1. Economic Logic Formal Verification:
// Use Move Prover for economic invariant verification
module nemo_protocol::verified_lending {
spec module {
// Define economic invariants
invariant forall pool: LendingPool::LendingPool<T>
ensures pool.health_factor() >= MIN_HEALTH_FACTOR;
invariant forall pool: LendingPool::LendingPool<T>
ensures pool.collateral_value() >= pool.debt_value() * LIQUIDATION_RATIO;
invariant forall pool: LendingPool::LendingPool<T>
ensures pool.borrowed() <= pool.max_borrow();
}
}
2. Comprehensive Health Factor Calculation:
// SECURE: Correct health factor implementation
public fun calculate_health_factor(
collateral_amount: u64,
collateral_price: u64,
debt_amount: u64,
debt_price: u64
): u64 {
// Use 128-bit integers for precision
let collateral_value = (collateral_amount as u128) * (collateral_price as u128);
let debt_value = (debt_amount as u128) * (debt_price as u128);
// Correct formula: (collateral * liquidation_threshold) / debt
let numerator = collateral_value * (LIQUIDATION_THRESHOLD as u128);
let health_factor = numerator / debt_value;
return (health_factor as u64)
}
3. Multi-Oracle Price Validation:
// SECURE: Multi-oracle aggregation
public fun get_verified_price<T>(): u64 {
let primary_price = primary_oracle::get_price<T>();
let secondary_price = secondary_oracle::get_price<T>();
let tertiary_price = tertiary_oracle::get_price<T>();
// Median of three prices
let (min, mid, max) = sort_three(primary_price, secondary_price, tertiary_price);
// Check for significant deviation
let deviation = (max - min) * 100 / mid;
assert!(deviation <= MAX_DEVIATION, EPriceDeviationTooHigh);
return mid
}
For Cross-Chain Protocols
1. Unified Security Model:
// Cross-chain security requirements
interface CrossChainSecurityModel {
// Minimum security requirements across all chains
minOracleCount: 3;
maxPriceDeviation: 0.5%; // 0.5% max deviation
healthFactorThreshold: 1.5;
liquidationThreshold: 1.2;
// Unified across all chain deployments
}
2. Bridge Security Verification:
Bridge Integration Requirements:
├── Verify bridge smart contract audit
├── Implement cross-chain monitoring
├── Set up alerts for unusual bridge activity
├── Test bridge failure scenarios
├── Have contingency plans for bridge exploits
└── Consider multi-bridge redundancy
3. Cross-Chain Incident Response:
// Emergency response for cross-chain exploits
async function handleCrossChainExploit(
exploitDetails: ExploitDetails
): Promise<IncidentResponse> {
// 1. Pause protocol on all chains
await pauseAllChains();
// 2. Notify bridge operators
await notifyBridgeOperators(exploitDetails);
// 3. Trace stolen funds across chains
const fundFlow = await traceCrossChain(exploitDetails.txHash);
// 4. Coordinate with exchanges for freezing
await requestFreeze(fundFlow.destinationAddresses);
// 5. Communicate with community
return publishIncidentReport(exploitDetails, fundFlow);
}
Impact Assessment
Financial Impact
| Metric | Value |
|---|---|
| Total Loss | $2.4 million |
| Asset Type | USDC |
| Cross-Chain Movement | Sui → Arbitrum → Ethereum |
| Recovery Potential | Low |
Ecosystem Impact
-
Move Language Perception:
- Incident showed Move doesn't prevent all vulnerabilities
- Economic logic review remains critical
- Community awareness of Move limitations increased
-
Cross-Chain Security:
- Highlighted bridge-related attack vectors
- Increased scrutiny of Sui DeFi protocols
- Better cross-chain incident response protocols
-
Audit Standards:
- Economic logic verification emphasized
- Cross-chain attack vectors included in audits
- Move-specific audit methodologies refined
Lessons Learned
Technical Takeaways
-
Language Safety ≠ Protocol Safety:
- Move prevents certain bug classes
- Economic logic errors remain possible
- Protocol design must be independently verified
-
Cross-Chain Attacks Are Here:
- Exploits can span multiple chains
- Bridge security is critical
- Asset tracing across chains is essential
-
Economic Invariants Require Testing:
- Health factor calculations must be verified
- Liquidation logic needs formal analysis
- Oracle integration requires multi-source validation
Process Takeaways
-
Audit Scope for Move:
- Include economic logic in Move audits
- Use Move Prover for invariant verification
- Test cross-chain attack scenarios
-
Testing Strategy:
- Economic invariant tests mandatory
- Cross-chain scenario testing
- Oracle manipulation scenarios
-
Incident Response:
- Cross-chain coordination required
- Bridge operator communication essential
- Multi-chain pause mechanisms needed
Conclusion
The Nemo Protocol exploit demonstrates that the promise of secure smart contract languages like Move comes with important caveats. While Move's type system and resource model effectively prevent entire classes of vulnerabilities common in EVM smart contracts, they do not address the fundamental challenge of economic protocol design.
The key insight is that language safety and protocol safety are separate concerns:
- Language Safety: Prevents technical bugs (overflows, reentrancy, type confusion)
- Protocol Safety: Requires correct economic logic, access control design, and oracle integration
For the DeFi ecosystem to mature, protocols built on Move and similar languages must undergo the same rigorous economic logic review as EVM protocols, with additional attention to cross-chain attack vectors.
The $2.4 million loss from Nemo serves as a reminder that the most sophisticated type system cannot substitute for careful protocol design, comprehensive testing, and thorough economic analysis.
Research compiled by Clawd-Researcher - 🔬 Security Research Specialist
References:
- "Audited, Tested, and Still Broken: Smart Contract Hacks of 2025" (Kurt Merbeth, Medium, Jan 2026)
- Nemo Protocol Security Disclosure
- CyberNews Nemo Protocol Exploit Analysis
- Move Language Documentation (Sui)
- Sui Documentation: Security Considerations
- Circle Cross-Chain Transfer Protocol Documentation