Analysis of the Vulnerability Found in the Smart Contract

Our analysis on the EOS SX vault attack in May 2021.

We are investigating an attack on the vault. The majority of the EOS and USDT in the vault have been stolen.❗️SX Vault attackDO NOT DEPOSIT in vaultWe will update EOSX so as to stop people from depositing further ASAP.We'll provide a complete-post mortem as soon as we complete our investigation.
EOS Nation is offering a 100,000 USDT bounty to the white hat hacker who identified the re-entry attack exploit on the smart contract.The reward will be transferred to the account of your choice once the 1,180,142.5653 EOS and 461,796.8968 USDT are returned to the account.
  • The attacker potghpfcmocs deposits a certain token, such as USDT and receives back the alternative token SXUSDT, all business as usual.
# Just an example
potghpfcmocs → 2 USDT → 2 USDT issued 20 SXUSDT to → potghpfcmocs 20 SXUSDT
// deposit - handle issuance (ex: EOS => SXEOS)
if ( deposit_itr != _vault.end() ) {
  • Now that the attacker has the alternative token funds, she can transfer them to the contract to obtain the original token, which in theory would have collected interests over time, but the attacker does it all immediately:
potghpfcmocs → 10 SXUSDT
require_recipient( from );
require_recipient( to );
// withdraw - handle retire (ex: SXEOS => EOS)
} else if ( supply_itr != _vault_by_supply.end() ) {
const extended_asset out = calculate_retire( id, quantity );extended_asset sx::vaults::calculate_retire( const symbol_code id, const asset payment )
const int64_t S0 = vault.deposit.quantity.amount;
const int64_t R0 =;
const int64_t p = (uint128_t(payment.amount) * S0) / R0;
return { p, vault.deposit.get_extended_symbol() };
// update internal deposit & supply
_vault_by_supply.modify( supply_itr, get_self(), [&]( auto& row ) {
row.deposit -= out; -= quantity;
row.last_updated = current_time_point();
transfer( account, get_self(), out, get_self().to_string() );
// send underlying assets to sender
transfer( get_self(), from, out, get_self().to_string() ); - borrow 0.0001 → potghpfcmocs 0.0001 USDT
potghpfcmocs → 0.0002 USDT - update id: USDT
// get balance from account
const asset balance = eosio::token::get_balance( contract, account, sym.code() );
// update balance
_vault.modify( vault, get_self(), [&]( auto& row ) {
row.deposit.quantity = balance + staked;
row.staked.quantity = staked;
row.last_updated = current_time_point();
const int64_t S0 = vault.deposit.quantity.amount;
const int64_t R0 =;
const int64_t p = (uint128_t(payment.amount) * S0) / R0;
// Just an example
potghpfcmocs → 10 SXUSDT → potghpfcmocs 2 USDT
// Just an example - retire quantity: 10 SXUSDT → potghpfcmocs 1 USDT - retire quantity: 10 SXUSDT
Block producers reached consensus to uphold the intent of code.Approximately 1.2M EOS and 462,000 USDT was stolen in a re-entry attack exploit on the flash loan smart contract that began on May 14 at 11:28 UTC.The and smart contracts were open-source, MSIGed, and passed security audits, however the re-entry exploit was not identified.All of the funds are safe under control of eosio.prods and will be returned to depositors.



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
EOS Costa Rica

EOS Block Producer candidate in the heart of the Americas. We stand for liberty and equality. Mainnet BP: costaricaeos ·