Secret Network
WebsiteDiscordGithub
  • šŸ‘‹INTRODUCTION
    • Secret Network Introduction
    • Secret Network Techstack
      • Private transactions - A quick summary
      • Blockchain Technology
        • Cosmos Basics
        • Tendermint
        • Cosmos SDK
        • IBC
        • CosmWasm
      • Privacy Technology
        • Encryption - Key Management
          • Overview
          • Key Derivation & Encryption Techniques
          • The Initialization Of Secret Network
          • Full Node Boostrap
          • Contract State Encryption
          • Transaction Encryption
          • Consensus seed rotation
        • Trusted Execution Environmentsā€Š (TEE) ā€”ā€Š Intel SGX
          • How Secret Network Uses SGX
          • SGX-SPS Security & Reliabillity
          • Remote Attestation
          • Trusted & Untrusted Core
          • Sealing
        • Private smart contracts - overview
  • šŸ’»Development
    • šŸ Getting Started
      • Setting Up Your Environment
        • Cargo.toml Best Practices (Crates vs Dependencies)
      • Compile and Deploy
      • Running the Application
      • Compile and Deploy on Secret testnet (best for Javascript devs)
      • Fullstack dApp Integration
    • šŸ¤“Secret Contracts
      • Secret Contracts & CosmWasm
        • Framework overview
        • Secret Contract Components
          • Instantiation Message
          • Execution Message
          • Query Message
          • Deps/DepsMut
          • Storage
            • Prefixed Storage
            • Singleton
            • Keymap
            • Append Store
            • Best practices
        • CosmWasm vs Secret CosmWasm
      • Secret Tokens (SNIP-20)
      • Contract - module call
      • Secret contract - Design Space/Features
        • Secret Contracts introduction
        • Gas/Fee usage
        • TPS and scalability
        • Privacy Essentials
        • Access Control
          • Viewing Keys
          • Permits
        • Trusted and untrusted data
        • Secret-VRF - on-chain Randomness
        • Privacy design
          • Mitigate privacy risks - full guide
          • Gas Evaporation & Tracking
        • Confidential Computing Layer
        • Fiat/Crypto Onboarding
        • Account abstraction
        • Fee abstraction
        • Wallet support
        • Bridge (messaging/tokens)
        • IBC (Hooks, PFM, Wasm)
        • Price Oracles
        • Auto Restaking
      • Permissioned Viewing
        • Viewing Keys
        • Permits
      • Cross Contract Communication
      • Submessages
        • get_contract_code_hash
      • Randomness API - Secret VRF
        • Native On-chain randomness
        • Randomness over IBC
      • Execution Finalization
      • Factory Contracts
      • Contract Migration
        • Manual - < v1.11
        • Native - from v1.11
      • Cross-deploy Vanilla CW and Secret Contracts
      • Testing Secret Contracts
        • Unit Tests
        • Continuous Integration
        • Datatype Handling - Uint, floats etc.
    • šŸ‘€Secret Contract - Reference, Guides, Examples
      • Starter guide - Millionaire's Problem
      • Reference Contracts
      • Open source dApps
      • Tools & Libraries
        • Network interaction SDKs
          • Secret.js (JavaScript)
          • SecretPy (Python)
          • SecretK (Kotlin)
          • Secret.NET
            • Snippets
              • Deploying a Contract
              • Send Native Coin
              • Query a Contract
              • Create a new Wallet
              • Permits
              • SNIP20
              • SNIP721
          • Shade.Js
        • LocalSecret - Devnet docker
        • Smart contract - Tools/Utils
          • Secret Toolkit
          • CW-Plus
          • Fadroma - SC framework
          • Hidden Gems
          • Other
            • Secret IDE
            • Polar
    • šŸ–¼ļøFrontend Development
      • Getting Started with SecretJS
        • Usage Examples
          • Sending Queries
          • Sending Messages
          • Contract Migration
          • Wallet Integrations
          • Query Permits
          • SNIP20 (SCRT Tokens)
          • SNIP721 (Secret NFTs)
      • Feegrant
        • Understanding Feegrant allowances
        • Grant allowances
        • Using grant allowances to execute transactions
        • Using the Fee Grant Faucet
    • šŸ“¬Deployment Addresses/ API Endpoints
      • Secret (SNIP 20) token contracts list
        • SNIP Asset naming guidelines
      • Connecting to the Network
        • API Endpoints Mainnet (Secret-4)
        • API Endpoints Testnet (Pulsar-3)
        • Usage examples
        • Comparison of endpoint types
      • Create your own SNIP-25 IBC Token
  • Secret AI
    • šŸ¤Introduction
    • šŸ—ļøArchitecture
    • šŸ‘©ā€šŸ’»Secret AI SDK
      • Setting Up Your Environment
      • Running the Application
    • šŸŖ™Economics
    • Smart Contract Reference
      • SubscriptionManager
      • WorkerManager
      • RewardsManager
  • 🌐SecretVM - Confidential Virtual Machines
    • šŸ¤Introduction
    • šŸ—ļøArchitecture
    • ā˜‘ļøAttestation
      • What is Attestation
      • Obtaining Attestation Data
      • Attestation Report - Key Fields
      • Chain of Trust
    • šŸLaunching a SecretVM
    • šŸ› ļøManaging SecretVM Lifecycle
    • āœ…Verifying a SecretVM
      • 🐢Full Verification
      • 🐰Quick Verification
    • šŸ’”Best Practices for Developers
    • šŸ“–Glossary
  • šŸ”“Confidential Computing Layer
    • šŸ§‘ā€šŸš€IBC Developer Toolkit
      • Basics
        • Overview
        • Cross-chain Messaging with IBC Hooks
          • Functions, Methods, and Data Structures
          • Typescript SDK
          • IBC-Hooks
        • IBC Relaying with Go Relayer
      • Usecases
        • Storing Encrypted Data on Secret Network
          • Key-Value store Developer Tutorial
        • Secret VRF for IBC with IBC-Hooks
        • Confidential Voting
        • Sealed Bid Auctions
      • Supported Networks
        • Mainnet
        • Testnet
    • šŸ¤Ethereum (EVM) Developer Toolkit
      • Basics
        • Overview
        • Connecting Metamask to Secret Network
        • SecretPath + Reown integration
        • Cross-chain Messaging
          • SecretPath
            • Architecture Overview
            • Detailed Architecture
            • SecretPath Developer Tutorials
            • Public EVM Gateway Architecture
            • How to deploy SecretPath on your chain
          • Axelar GMP
            • Architecture Overview
            • Axelar GMP Developer Tutorial
      • Usecases
        • Storing Encrypted Data on Secret Network
          • Key-Value store Developer Tutorial
        • Sealed Bid Auction
          • Sealed Bid Auction Developer Tutorial
        • Confidential Voting
          • Confidential Voting Developer Tutorial with SecretPath
        • VRF
          • Implementing VRF into any EVM Contract
          • VRF Developer Tutorial
          • Performance figures of SecretVRF vs competitors
          • Using encrypted payloads for VRF
          • Converting from Chainlink VRF to Secret VRF in four steps
        • Confidential Document Sharing
        • Tokens
          • From EVM to Secret
      • Supported Networks
        • EVM
          • EVM Mainnet
          • EVM Testnet
          • Gateway Contract ABI
        • Secret Gateway
          • SecretPath mainnet (secret-4) contracts
          • SecretPath testnet (pulsar-3) contracts
    • šŸ™ŒSolana Developer Toolkit
      • Usecases
        • Storing Encrypted Data on Secret Network
          • Key-value Store Developer Tutorial
        • VRF
          • VRF Developer Tutorial
      • Program IDs
        • Solana Mainnet & Testnet
        • Gateway Contract IDL
  • 🤫Overview, Ecosystem and Technology
    • šŸš€Secret Network Overview
      • The SCRT coin
      • Private Tokens
      • Use Cases
        • Decentralized Finance (DeFi)
        • Art And Digital Media
        • Gaming
        • Data Privacy
        • Payments And Transactions
        • Communication
      • The technology
      • History
      • Roadmap (Core development)
        • Secret 2.0
      • Where To Buy SCRT?
      • Using the Testnet
    • 🐸Ecosystem Overview
      • Wallets
      • Applications
      • Explorers & tools
      • Funding
        • SCRT Labs Grants
        • Dilutive funding/VC raise
        • Community Pool
        • Developer bounties
          • SCRT Labs bounties [on-hold]
          • CCBL [on-hold]
          • CCR [On-hold]
        • Application specific
          • Shade Grants
      • Contributors & Entities
        • Validators
        • SCRT Labs
        • Secret Foundation
        • Secret Committees
          • Support
          • Governance
      • Secret Network Dictionary
  • šŸ”§Infrastructure
    • šŸ”“Use SecretCLI
      • Secretcli vs. Secretd
      • Install
      • Configuration
      • Address Types
      • Key Types
      • Generating Keys
      • Viewing Keys
      • Query Transactions
      • Send Tokens
      • Multisig Keys
      • Multisig Transactions
      • Transaction Broadcasting
      • Fees & Gas
      • Fee Distribution
      • Secret Contracts
      • Slashing
      • Minting
      • Delegating
      • Restake
      • Nodes
      • Governance
        • Creating Governance Proposals
        • Query Proposals
        • Deposits
        • Voting
    • šŸ”Use Ledger hardware wallet
      • šŸ”Ledger with SecretCLI
    • šŸ–„ļøRunning a node/validator
      • Setting up a node/validator
        • Hardware setup
          • Hardware Compliance
          • VPS/Bare-Metal Compliance
            • Leaseweb Setup
            • PhoenixNAP Setup
            • Psychz Setup
            • nForce Setup
            • Vultr Setup
            • OVHCloud Setup
            • Microsoft Azure Setup
          • Patching your Node
          • Enclave verification
          • Registration troubleshooting
        • Testnet Setup
          • Install SGX
          • Install secretd
          • Setup Full Node
          • Testnet State Sync
          • Becoming a Testnet Validator
          • Installing CLI & Creating A New Address
        • Mainnet Setup
          • Install SGX
          • Install secretd
          • Setup Full Node
          • Quicksync / Snapshot
          • Statesync
          • Becoming A Validator
          • Installing CLI & Creating A New Address
      • Maintaining a node/validator
        • Slashing information
        • Migrating a Validator
        • Troubleshooting
        • Validator Backup
        • Server security
          • SSH authentication
          • Server configuration
          • Uncomplicated-Firewall (UFW)
          • Local CLI
        • Node Monitoring
          • Prometheus
            • Environment Preperation
            • Install Node Exporter
            • Install Prometheus
            • Configuring Prometheus
          • Grafana
            • Install Grafana
            • Grafana Dashboard
            • Next Steps
          • Docker
            • Install Docker
            • Configuration
            • Start Containers
            • Grafana Dashboard
            • Application Ports
            • Stop Containers
          • Goaccess
            • Install Goaccess
            • Setup Goaccess
        • Helpful commands
          • Query Validators
          • Bond Tokens
          • Withdraw Rewards
          • Query Delegations
          • Unbond Tokens
          • Query Unbonding-Delegations
          • Redelegate Tokens
          • Query Redelegations
          • Query Parameters
          • Query Pool
          • Query Delegations To Validator
      • API Noderunning
        • Running Multiple Nodes on the Same Server
        • Node Loadbalancing using Nginx
          • Setup Nginx
          • Example Nginx config
        • Using Auto heal to improve cluster uptime for Nginx
      • Sentry and Archive nodes
        • Mantlemint
        • Sentry Nodes
        • Archive Nodes
    • ā›“ļøIBC Relayers
      • Hermes
      • RLY
      • IBC channel database
    • šŸ†™Upgrade Instructions
      • v1.13
      • v1.12
      • v1.11
      • v1.10
      • v1.9
      • v1.8
      • v1.7
      • Shockwave Omega v1.6
      • v1.5
      • Shockwave Delta v1.4
      • Shockwave Delta v1.4 (Testnet)
      • Shockwave Alpha v1.3
      • Cosmovisor
      • Vulcan Network Upgrade (OLD)
    • ā˜ ļøPostmortems
      • SNIP-20 leaks
      • xApic
      • Secpk-Verifications Bloat
      • Earn Contract Exploit
      • Testnet Halt 95
    • āœļøContribute to the documentation
      • Report Bugs
      • Suggest Enhancements
      • First Contribution Guide
      • Pull Request Templates
        • Update Documentation
        • Bug Fix
        • Improve Performance
        • Change Functionality
      • Style Guide
    • 🌊Versioning & Changelog
      • Secret Network v1.13
      • Secret Network v1.12
      • Secret Network v1.11
      • Secret Network v1.10
      • Secret network v1.9
      • Secret Network v1.7/1.8
      • Secret Network v1.6
      • Secret Network v1.5
      • Secret Network v1.4 (CosmWasm 1.0)
Powered by GitBook
On this page
  • September 2021 Earn Contract Exploit
  • Description
  • What Happened
  • Exploit Flow
  • Resolution
  • Conclusion And Next Steps

Was this helpful?

Edit on GitHub
Export as PDF
  1. Infrastructure
  2. Postmortems

Earn Contract Exploit

September 2021 Earn Contract Exploit

  • Chain id: secret-2

  • Date: 13/09/2021 3am UTC

  • Related issues: https://forum.scrt.network/t/earn-contract-exploit-post-mortem/4426

Description

Hi everyone,

A couple of weeks ago, a vulnerability in the SecretSwap Earn contracts (also known as the SPY contracts) was discovered and exploited. As far as we know, this is the first Rust/WASM-based contract exploit case, which is interesting in and by itself, and specifically, the first one on Secret Network where the interactions with said contract were all private (more on this below).

At this point, it’s important to clarify that Secret Network was in no way exploited, neither were the bridges, and that all funds are safe (with the exception of some minor network-upgrade related cases we are actively resolving, accounting for ~$50K). Like in any other major smart-contract chain, including ETH, BSC, and others, smart contract-related vulnerabilities are a potential risk. All we can do is mitigate the risk (and improve on our best practices in doing so), but it cannot be completely eliminated. In this case, the vulnerability, as is described below in a quite technical manner, was not an easy one to uncover and was quite sophisticated.

What Happened

The exploit took advantage of a missing input integrity check in the SPY contracts’ (=reward pools’ contracts) deposit function to arbitrarily generate rights to withdraw assets from the SPY contracts. We’ll go over a normal flow of a deposit to a SPY contract, and then how it was exploited. Keep in mind that there are 5 types of contracts involved here:

Secret Tokens - contracts such as sSCRT, sETH, sXMR, etc. Swap Pairs - which handle trading between pairs of Secret Tokens. LP Tokens - which represent liquidity-provider’s portion of the liquidity pools in the Swap Pairs. SPY contracts - which allow users to deposit LP tokens in exchange for accumulating SEFI rewards. The Master Contract - which orchestrates the allocation and minting of $SEFI to the SPY contracts. A valid flow of depositing assets in SPY contracts works like this:

Alice has eligible LP tokens. Alice executes a send transaction to the SPY contract, with a deposit inner message:

export const DepositRewards = async (params: {
  secretjs: AsyncSender;
  recipient: string;
  address: string;
  amount: string;
  fee?: StdFee;
}): Promise<string> => {
  const tx = await Snip20Send({
    msg: 'eyJkZXBvc2l0Ijp7fX0K', // '{"deposit":{}}' -> base64
    ...params,
  });
  console.log(tx)
  return 'yooyoo';
};

The Receive handler of the SPY contract receives the message above with the LP funds amount, which is then parsed and handled as described below.

The integrity of the received assets (Alice’s locked assets) relies on the integrity of the LP token; we have to trust the LP token to provide an accurate amount of received tokens i.e. we trust amount that is received in the receive call. The LP contract constructs the receive message with the correct information here: (full code section) 3

fn try_add_receiver_api_callback<S: ReadonlyStorage>(
    messages: &mut Vec<CosmosMsg>,
    storage: &S,
    recipient: &HumanAddr,
    msg: Option<Binary>,
    sender: HumanAddr,
    from: HumanAddr,
    amount: Uint128,
) -> StdResult<()> {
    let receiver_hash = get_receiver_hash(storage, recipient);
    if let Some(receiver_hash) = receiver_hash {
        let receiver_hash = receiver_hash?;
        let receiver_msg = Snip20ReceiveMsg::new(sender, from, amount, msg);
        let callback_msg = receiver_msg.into_cosmos_msg(receiver_hash, recipient.clone())?;

        messages.push(callback_msg);
    }
    Ok(())
}

Upon receive, the SPY contract first needs to get the amount of rewards that the Master contract has allocated to it so far. This information needs to be collected before the other state changes occur (either a deposit or a redeem). Therefore, the SPY contract calls the Master contract with update_allocation. Since there is no ability to call an external contract function inline from another contract function, the SPY contract also provides a callback message (in this case called hook) that the Master, in turn, will send back to the same SPY contract, to proceed with the deposit operation: Building the hook message in the SPY contract: update_allocation( env, config, Some(to_binary(&LPStakingHookMsg::Deposit { from, amount: Uint128(amount), })?), ) Wrapping the hook with update_allocation:

fn update_allocation(env: Env, config: Config, hook: Option<Binary>) -> StdResult<HandleResponse> {
    Ok(HandleResponse {
        messages: vec![WasmMsg::Execute {
            contract_addr: config.master.address,
            callback_code_hash: config.master.contract_hash,
            msg: to_binary(&MasterHandleMsg::UpdateAllocation {
                spy_addr: env.contract.address,
                spy_hash: env.contract_code_hash,
                hook,
            })?,
            send: vec![],
        }
        .into()],
        log: vec![],
        data: None,
    })
}

That message is handled by the Master contract, and then the hook is sent back to the SPY contract like this:

// Notify to the spy contract on the new allocation
messages.push(
    WasmMsg::Execute {
        contract_addr: spy_address.clone(),
        callback_code_hash: spy_hash,
        msg: to_binary(&LPStakingHandleMsg::NotifyAllocation {
            amount: Uint128(rewards),
            hook,
        })?,
        send: vec![],
    }
    .into(),
);

The Master contract calls the SPY with notify_allocation which contains hook. The SPY contract proceeds to finish the deposit operation. Note that the amount argument here came originally from the receive function, therefore trusted and should be valid.

Exploit Flow

Bob (attacker) executes a transaction that calls directly to the Master contract with update_allocation with an inner deposit message (as hook). Note that update_allocation requires no permissions and can be called by anyone. The Master contract calls notify_allocation on the SPY contract with the provided hook. Since notify_allocation relies on the data originally coming from a receive message, there are no further integrity checks on amount, and the hook is interpreted as a valid deposit message. In the SPY contract, the deposit_hook function is called with the parameters from the deposit, and increments Bob’s balance in the SPY contract: user.locked += amount;

Bob’s deposit message is successfully processed and he is given a right to withdraw funds equivalent to the amount he provided i.e. Bob can withdraw assets that were not deposited by him.

Resolution

As soon as the exploit became known, the entire Enigma team, many of the network’s validators and other members of the community, such as the Secret Foundation, committee members and leads, bridge operators and many others, came together to devise an action plan. Despite the many difficulties in coordinating so many actors in a decentralized ecosystem across many time zones, we were all able to coordinate a network upgrade that corrected the situation. While not an easy decision, given the funds at stake, this course of action was accepted by the majority of validators in the network.

In addition, to prevent funds from flowing out of the network, we communicated with all bridge operators and exchanges to ensure withdrawals outside of the network are temporarily disabled. This again required the interaction of many parties in the community and outside of it, and we are grateful for everyone who participated and assisted.

In particular, I’d like to also use this opportunity to thank my own team (Enigma), for staying up for 40+ hours while ensuring the vulnerability is found and patched, and for taking a leading part in coordinating all the different parties until a successful resolution.

Currently, everything in the network and all of its applications (including SecretSwap and the ETH/BSC bridges) are back to normal activity. We expect the Monero bridge to activate shortly as well, and we can say that the new Earn contracts, which would require migrating liquidity from the old (vulnerable) Earn contracts, are coming soon (next week at the latest). Given the privacy features of the network, it’s not possible to easily withdraw unclaimed SEFI from the old rewards contracts. This means that quite a lot of SEFI will in fact be burned. In addition, no new SEFI has been minted in the past few weeks, reducing the effective SEFI supply. Some of that supply will be reintroduced as compensation for liquidity providers who stayed and will migrate to the new contracts, in the form of accelerated rewards in the first few days.

Conclusion And Next Steps

There was a very sophisticated vulnerability in a Secret Contract. The network was never compromised, nor were any of the bridges. Nevertheless, in a collective action, the community came together and performed a network upgrade that ensured funds’ safety.

At this point, everything is back to normal operation, with the exception of the new, patched, Earn contracts (and by extension – governance) that will be re-introduced in the next week or so. These will require users to migrate, and will initially over-compensate LP’s unclaimed rewards loss. At the same time, a substantial amount of SEFI were effectively burned, thus reducing its overall supply.

Hope this clarifies the situation. We would like to remind everyone that we have a very generous bug/exploit bounty program, and that we always recommend taking a responsible disclosure course of action (we will make it worthwhile). For those who are interested please e-mail us at info (at) enigma (dot) co.

Best, Guy Enigma CEO

PreviousSecpk-Verifications BloatNextTestnet Halt 95

Last updated 5 months ago

Was this helpful?

šŸ”§
ā˜ ļø