[{"data":1,"prerenderedAt":118},["ShallowReactive",2],{"blog-archive:research":3},{"categories":4,"articles":13},[5,9],{"name":6,"slug":7,"articleCount":8},"Research","research",16,{"name":10,"slug":11,"articleCount":12},"Product Updates","product-updates",14,{"items":14,"total":8,"page":116,"pageSize":117},[15,28,38,48,58,69,79,89,99,107],{"slug":16,"category":7,"categoryLabel":6,"subcategoryLabel":17,"authorName":18,"title":19,"excerpt":20,"contentHtml":21,"coverUrl":22,"publishedAt":23,"updatedAt":24,"readTime":25,"cover":22,"hasCover":26,"coverAlt":27},"sui-move-security-why-legacy-packages-can-still-put-shared-objects-at-risk-after-an-upgrade-fb5a67","Industry Research","MoveBit","Sui Move Security: Why Legacy Packages Can Still Put Shared Objects at Risk After an Upgrade","Upgrading a Sui Move Package does not automatically disable its previous versions. Each upgrade publishes a new Package ID, while earlier versions remain on-chain. If other modules, routers, or clients continue to call a legacy Package, and multiple versions can modify the same Shared Object, conflicting assumptions about shared state can introduce cross-version vulnerabilities.","\u003Ch1>The BlueMove DEX Exploit: Cross-Version Reserve Desynchronization and LP Inflation\u003C\u002Fh1>\n\u003Cp class=\"docx-align-justify\">\u003Cstrong>Author:\u003C\u002Fstrong> MoveBit (@MoveBit_)\u003Cbr>\u003Cstrong>Date:\u003C\u002Fstrong> October 21, 2026\u003Cbr>\u003Cstrong>Source:\u003C\u002Fstrong> \u003Ca href=\"https:\u002F\u002Fx.com\u002FMoveBit_\u002Fstatus\u002F2112781636664463510\" rel=\"nofollow\">X Post\u003C\u002Fa>\u003C\u002Fp>\n\u003Chr>\n\u003Ch2>Introduction: Why Upgrading a Package Does Not Eliminate Legacy Security Risks\u003C\u002Fh2>\n\u003Cp class=\"docx-align-justify\">Upgrading a Sui Move Package does not automatically disable its previous versions. Each upgrade publishes a new Package ID, while earlier versions remain on-chain. If other modules, routers, or clients continue to call a legacy Package, and multiple versions can modify the same Shared Object, conflicting assumptions about shared state can introduce cross-version vulnerabilities.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">This risk is particularly significant in DeFi protocols. Changes to asset storage, reserve accounting, or business logic can leave legacy execution paths operating under outdated assumptions. When different Package versions modify the same state, individually valid operations can combine to violate the protocol&#39;s accounting invariants and create exploitable discrepancies.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">On July 11, 2026, BlueMove, a DEX in the Sui ecosystem, suffered an exploit. A technical analysis published on the Sui Developer Forum in August identified inconsistent updates to the shared \u003Ccode>reserve_x\u003C\u002Fcode> field across callable Package versions as a key factor. The analysis estimated that approximately 714,000 SUI was drained over roughly 23 minutes, representing a loss of about $528,000 at the time.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">\u003Cstrong>The key takeaway:\u003C\u002Fstrong> securing a Sui upgrade requires verifying every still-callable Package version, not just the latest implementation. All versions must preserve the same set of Shared Object state invariants.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">MoveBit, a flagship sub-brand of BitsLab, examines the incident through the lens of Sui Package versioning, Shared Object security, and Move smart contract auditing. Drawing on publicly available bytecode decompilation and on-chain analysis, this article traces the reserve-accounting flaw, explains how it inflated LP minting and enabled withdrawals, and examines practical approaches to isolating legacy code and migrating state safely.\u003C\u002Fp>\n\u003Cblockquote>\n\u003Cp class=\"docx-align-justify\">BlueMove&#39;s original source code has not been publicly released. The technical analysis below is based on publicly available bytecode decompilation and on-chain transaction research. All code snippets are simplified illustrations of the underlying mechanisms, not verbatim reproductions of the project&#39;s source code.\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Chr>\n\u003Ch2>1. Sui Package Upgrades: Why Legacy Code Remains Callable\u003C\u002Fh2>\n\u003Ch3>1.1 Each Upgrade Creates a New Package ID\u003C\u002Fh3>\n\u003Cp class=\"docx-align-justify\">Sui Move Packages are immutable on-chain code objects. An upgrade publishes a new Package version rather than modifying the existing version in place.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">A protocol may therefore have multiple deployed versions:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>V1\u003C\u002Fstrong> — Package ID: \u003Ccode>0x...\u003C\u002Fcode> (original)\u003C\u002Fli>\n\u003Cli>\u003Cstrong>V2\u003C\u002Fstrong> — Package ID: \u003Ccode>0x...\u003C\u002Fcode> (upgrade)\u003C\u002Fli>\n\u003Cli>\u003Cstrong>V3\u003C\u002Fstrong> — Package ID: \u003Ccode>0x...\u003C\u002Fcode> (latest)\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp class=\"docx-align-justify\">Each version has its own Package ID. A transaction invokes the version referenced by its call path. Dependencies that reference an older Package do not automatically switch to the latest version when an upstream Package is upgraded.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">Deploying V3 therefore does not, by itself, invalidate V1. If legacy functions remain callable and can access the relevant objects, they may continue to execute.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">\u003Cstrong>Reference:\u003C\u002Fstrong> \u003Ca href=\"https:\u002F\u002Fdocs.sui.io\u002Fconcepts\u002Fsui-move-concepts\u002Fpackages\u002Fupgrade\" rel=\"nofollow\">Sui Documentation: Package Versioning\u003C\u002Fa>\u003C\u002Fp>\n\u003Ch3>1.2 Packages Define Logic; Shared Objects Hold State\u003C\u002Fh3>\n\u003Cp class=\"docx-align-justify\">In an automated market maker (AMM), the Package defines swap, liquidity provision, withdrawal, and reserve-update logic. Shared Objects hold the pool&#39;s balances, reserves, and LP supply.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">The architecture can be represented as follows:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>┌─────────────────────────────────────────┐\n│              Shared Pool Object          │\n│  ┌─────────────────────────────────┐    │\n│  │ reserve_x \u002F reserve_y           │    │\n│  │ lp_supply                       │    │\n│  │ token_x \u002F token_y (or Escrow)   │    │\n│  └─────────────────────────────────┘    │\n└─────────────────────────────────────────┘\n         ↑                    ↑\n         │                    │\n    ┌────┴────┐          ┌────┴────┐\n    │  V1     │          │  V3     │\n    │ Package │          │ Package │\n    └─────────┘          └─────────┘\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp class=\"docx-align-justify\">When multiple Package versions can modify the same Pool, they must preserve consistent state invariants.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">Suppose V1 stores assets directly in \u003Ccode>pool.token_x\u003C\u002Fcode>, while V3 moves them into \u003Ccode>EscrowCoinsV2\u003C\u002Fcode>. If both versions update \u003Ccode>reserve_x\u003C\u002Fcode> using different balance sources, the reserve field can become inconsistent with the actual distribution of assets.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">Each version may behave as designed in isolation. The vulnerability emerges when their differing assumptions collide on the same Shared Object.\u003C\u002Fp>\n\u003Ch3>1.3 Upgrade Compatibility Does Not Guarantee Business-Logic Consistency\u003C\u002Fh3>\n\u003Cp class=\"docx-align-justify\">Sui&#39;s Package upgrade compatibility rules govern aspects such as public function signatures and struct layouts. Passing these checks does not guarantee that different versions preserve the same business invariants.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">For example, V1 may treat \u003Ccode>reserve_x\u003C\u002Fcode> as the Pool&#39;s directly held balance, while V3 treats it as the balance held in Escrow. If both versions can update the same field, its value may no longer have a consistent meaning across the protocol.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">A secure upgrade therefore requires more than checking the latest code. It also requires validating shared-state semantics, business invariants, and execution paths across Package versions.\u003C\u002Fp>\n\u003Chr>\n\u003Ch2>2. Root Cause: Two Package Versions Update \u003Ccode>reserve_x\u003C\u002Fcode> Using Different Balances\u003C\u002Fh2>\n\u003Cp class=\"docx-align-justify\">Public bytecode analysis identifies two callable Package versions as central to the BlueMove incident.\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>V1\u003C\u002Fstrong> stores assets in the Pool&#39;s \u003Ccode>token_x\u003C\u002Fcode> and \u003Ccode>token_y\u003C\u002Fcode> fields.\u003C\u002Fli>\n\u003Cli>The newer version uses \u003Ccode>EscrowCoinsV2\u003C\u002Fcode> for asset storage while continuing to maintain reserve values in shared Pool fields.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch3>2.1 V1 Reserve-Update Logic\u003C\u002Fh3>\n\u003Cp class=\"docx-align-justify\">The relevant V1 logic can be represented as follows:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>\u002F\u002F Simplified V1 reserve update\nfun update_reserves(pool: &amp;mut Pool) {\n    pool.reserve_x = pool.token_x.value();\n    pool.reserve_y = pool.token_y.value();\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp class=\"docx-align-justify\">V1 derives the reserves from the balances held directly in the Pool. After this update, the following invariant holds:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>pool.reserve_x == pool.token_x.value()\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp class=\"docx-align-justify\">This relationship remains valid as long as subsequent V1 calculations use the same balance source.\u003C\u002Fp>\n\u003Ch3>2.2 Reserve-Update Logic in the Newer Version\u003C\u002Fh3>\n\u003Cp class=\"docx-align-justify\">The newer version derives its reserves from Escrow:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>\u002F\u002F Simplified newer version reserve update\nfun update_reserves(pool: &amp;mut Pool, escrow: &amp;EscrowCoinsV2) {\n    pool.reserve_x = escrow.token_x.value();\n    pool.reserve_y = escrow.token_y.value();\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp class=\"docx-align-justify\">This implementation maintains a different invariant:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>pool.reserve_x == escrow.token_x.value()\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp class=\"docx-align-justify\">The difference is fundamental:\u003C\u002Fp>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Version\u003C\u002Fth>\n\u003Cth>Balance Source for \u003Ccode>reserve_x\u003C\u002Fcode>\u003C\u002Fth>\n\u003Cth>Meaning of \u003Ccode>reserve_x\u003C\u002Fcode>\u003C\u002Fth>\n\u003C\u002Ftr>\n\u003C\u002Fthead>\n\u003Ctbody>\u003Ctr>\n\u003Ctd>V1\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>pool.token_x\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Direct Pool balance\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd>Newer\u003C\u002Ftd>\n\u003Ctd>\u003Ccode>escrow.token_x\u003C\u002Fcode>\u003C\u002Ftd>\n\u003Ctd>Escrow balance\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftbody>\u003C\u002Ftable>\n\u003Cp class=\"docx-align-justify\">When the two balances differ, the versions can write different values into the same field.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">The last reserve update can change the meaning of \u003Ccode>reserve_x\u003C\u002Fcode>: V1 treats it as the Pool&#39;s direct balance, while the newer version treats it as the Escrow balance.\u003C\u002Fp>\n\u003Ch3>2.3 Why This Is a Cross-Version Vulnerability\u003C\u002Fh3>\n\u003Cp class=\"docx-align-justify\">Consider the following state:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>Escrow balance:       350,000 SUI\nPool direct balance:    7,022 SUI\nShared reserve_x:       7,022 SUI\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp class=\"docx-align-justify\">Here, \u003Ccode>reserve_x\u003C\u002Fcode> matches the Pool&#39;s direct balance but is roughly 50 times smaller than the Escrow balance.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">If the newer version uses \u003Ccode>reserve_x\u003C\u002Fcode> as the denominator in its LP minting formula, it can misinterpret the difference between these balances as newly added liquidity.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">V1&#39;s reserve update may be internally consistent, and the newer version&#39;s LP formula may be arithmetically correct. The flaw arises when the newer version interprets a value written under V1&#39;s accounting model as though it represented the Escrow balance.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">This is why cross-version security analysis must cover historical Packages, shared objects, and state transitions across functions rather than focusing exclusively on the latest implementation.\u003C\u002Fp>\n\u003Chr>\n\u003Ch2>3. How LP Minting Amplifies the Accounting Flaw\u003C\u002Fh2>\n\u003Ch3>3.1 LP Minting Must Reflect Actual Deposits\u003C\u002Fh3>\n\u003Cp class=\"docx-align-justify\">In a simplified AMM, the amount of LP tokens minted can be expressed as:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>ΔLP = S × (Δx \u002F R_x)\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp class=\"docx-align-justify\">Where:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Ccode>Δx\u003C\u002Fcode> is the amount of assets actually deposited.\u003C\u002Fli>\n\u003Cli>\u003Ccode>S\u003C\u002Fcode> is the LP supply before minting.\u003C\u002Fli>\n\u003Cli>\u003Ccode>R_x\u003C\u002Fcode> is the corresponding reserve under the authoritative accounting model.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp class=\"docx-align-justify\">Both the deposit amount and the reserve must reflect the same asset state. If \u003Ccode>reserve_x\u003C\u002Fcode> is inconsistent with the actual reserve, the formula can produce an inflated result without any arithmetic overflow.\u003C\u002Fp>\n\u003Ch3>3.2 The BlueMove Flaw: Miscalculating the Deposit Amount\u003C\u002Fh3>\n\u003Cp class=\"docx-align-justify\">The relevant minting logic can be simplified as follows:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>\u002F\u002F Simplified LP minting (newer version)\nfun mint_lp(pool: &amp;mut Pool, deposit_x: u64) -&gt; u64 {\n    let current_x = escrow.token_x.value();  \u002F\u002F Actual Escrow balance\n    let delta = current_x - pool.reserve_x;  \u002F\u002F Assumes reserve_x == previous Escrow\n    let lp_to_mint = pool.lp_supply * delta \u002F pool.reserve_x;\n    \u002F\u002F ...\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp class=\"docx-align-justify\">The calculation assumes that \u003Ccode>pool.reserve_x\u003C\u002Fcode> represents the Escrow balance before the deposit.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">If V1 has overwritten \u003Ccode>reserve_x\u003C\u002Fcode> with the Pool&#39;s direct balance, then:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Ccode>current_x\u003C\u002Fcode> = Escrow balance\u003C\u002Fli>\n\u003Cli>\u003Ccode>reserve_x\u003C\u002Fcode> = Pool direct balance\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp class=\"docx-align-justify\">The expression \u003Ccode>current_x - reserve_x\u003C\u002Fcode> no longer measures the assets deposited in the current transaction. Instead, it includes the historical difference between two separate balances.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">The denominator is also too small, further inflating the LP output.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">The attacker can therefore exploit inconsistent accounting semantics without triggering an integer overflow.\u003C\u002Fp>\n\u003Chr>\n\u003Ch2>4. Numerical Walkthrough: How a Small Deposit Can Produce Excessive LP Shares\u003C\u002Fh2>\n\u003Cp class=\"docx-align-justify\">The following figures illustrate the mechanism described in the public analysis. They are representative values, not a complete historical snapshot of a specific pool.\u003C\u002Fp>\n\u003Ch3>4.1 Initial State\u003C\u002Fh3>\n\u003Cpre>\u003Ccode>Escrow balance:   350,000 SUI\nPool balance:       7,022 SUI\nreserve_x:          7,022 SUI\nLP supply:          1,000\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp class=\"docx-align-justify\">A V1 swap updates \u003Ccode>reserve_x\u003C\u002Fcode> to the Pool&#39;s direct balance. Although Escrow holds 350,000 SUI, the newer version uses 7,022 SUI as its reserve baseline.\u003C\u002Fp>\n\u003Ch3>4.2 Step One: Add Liquidity Through the Newer Version\u003C\u002Fh3>\n\u003Cp class=\"docx-align-justify\">The attacker deposits approximately 0.057 SUI into the Escrow used by the newer version, alongside the corresponding amount of the other token.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">The updated Escrow balance becomes:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>350,000 + 0.057 = 350,000.057 SUI\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp class=\"docx-align-justify\">However, \u003Ccode>reserve_x\u003C\u002Fcode> remains at 7,022 SUI.\u003C\u002Fp>\n\u003Cpre>\u003Ccode>Δx (perceived) = 350,000.057 - 7,022 ≈ 342,978 SUI\nΔLP = 1,000 × (342,978 \u002F 7,022) ≈ 48,843 LP tokens\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp class=\"docx-align-justify\">A deposit of approximately 0.057 SUI thus produces around 48,843 LP tokens, roughly 48.8 times the existing LP supply.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">The problem is the incorrect comparison between Escrow&#39;s balance and the Pool&#39;s direct balance, not an arithmetic overflow.\u003C\u002Fp>\n\u003Ch3>4.3 Step Two: Withdraw Liquidity Through V1\u003C\u002Fh3>\n\u003Cp class=\"docx-align-justify\">According to the public analysis, the attack then calls V1&#39;s \u003Ccode>remove_liquidity\u003C\u002Fcode> function. The legacy withdrawal logic reads the Pool&#39;s direct balance rather than the Escrow balance.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">Its calculation can be simplified as follows:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>Attacker share = new_lp \u002F total_lp\nWithdrawal = pool.token_x.value() × attacker_share\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp class=\"docx-align-justify\">Using the representative figures:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>Existing LP supply = 1,000\nNew LP minted      = 48,843\nTotal LP supply    = 49,843\n\nAttacker share = 48,843 \u002F 49,843 ≈ 97.99%\n\nWithdrawal ≈ 7,022 × 0.9799 ≈ 6,881 SUI\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp class=\"docx-align-justify\">The attacker can therefore withdraw approximately 6,881 SUI from the Pool&#39;s direct balance.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">These assets come from \u003Ccode>pool.token_x\u003C\u002Fcode>, not directly from the 350,000 SUI held in Escrow. The Escrow balance inflates the LP minting calculation, allowing the attacker to claim a disproportionate share of the Pool&#39;s directly held assets.\u003C\u002Fp>\n\u003Ch3>4.4 Why the Attack Works Within a Single Transaction\u003C\u002Fh3>\n\u003Cp class=\"docx-align-justify\">The public analysis indicates that the attacker used a Programmable Transaction Block (PTB) to call the newer version&#39;s \u003Ccode>add_liquidity_returns\u003C\u002Fcode> function and then V1&#39;s \u003Ccode>remove_liquidity\u003C\u002Fcode> function within the same transaction.\u003C\u002Fp>\n\u003Cpre>\u003Ccode>PTB:\n  1. Call newer.add_liquidity_returns(...) → returns LP tokens\n  2. Call V1.remove_liquidity(LP tokens)   → withdraws from Pool\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp class=\"docx-align-justify\">The LP tokens returned by \u003Ccode>add_liquidity_returns\u003C\u002Fcode> can be passed to subsequent commands. This allows the attacker to combine the newer version&#39;s minting logic with the legacy withdrawal logic in a single transaction.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">The public analysis describes a transaction containing 49 programmable commands and repeated call sequences across multiple pools. It estimates that approximately 363 pools were affected, with total transfers of around 714,000 SUI.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">\u003Cstrong>Source:\u003C\u002Fstrong> \u003Ca href=\"https:\u002F\u002Fforums.sui.io\u002Ft\u002Fbluemove-was-not-an-overflow-bug-how-a-cross-version-reserve-desync-drained-714-000-sui\u002F49409\" rel=\"nofollow\">Sui Developer Forum: BlueMove Cross-Version Reserve Desynchronization Analysis\u003C\u002Fa>\u003C\u002Fp>\n\u003Chr>\n\u003Ch2>5. Why Destroying the UpgradeCap Does Not Disable Legacy Code\u003C\u002Fh2>\n\u003Cp class=\"docx-align-justify\">The public analysis reports that BlueMove&#39;s \u003Ccode>UpgradeCap\u003C\u002Fcode> was destroyed on June 3, 2026, while the exploit occurred on July 11.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">Destroying an \u003Ccode>UpgradeCap\u003C\u002Fcode> can permanently prevent further upgrades to a Package. It does not remove historical Packages from the blockchain or invalidate their functions. Legacy code can remain callable through its original Package ID.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">Upgrade authorization and legacy-code control are separate security concerns. Preventing further upgrades does not prevent an older version from modifying shared state.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">\u003Cstrong>Reference:\u003C\u002Fstrong> \u003Ca href=\"https:\u002F\u002Fdocs.sui.io\u002Fconcepts\u002Fsui-move-concepts\u002Fpackages\u002Fupgrade\" rel=\"nofollow\">Sui Documentation: Upgrading Packages\u003C\u002Fa>\u003C\u002Fp>\n\u003Chr>\n\u003Ch2>6. Remediation: Object Version Checks and Legacy-State Isolation\u003C\u002Fh2>\n\u003Cp class=\"docx-align-justify\">The appropriate remediation depends on whether the protocol incorporated version control into its Shared Object design from the outset.\u003C\u002Fp>\n\u003Ch3>6.1 Approach One: Add Object Version Checks in the Initial Design\u003C\u002Fh3>\n\u003Cp class=\"docx-align-justify\">Sui recommends designing Package version management into systems that interact with Shared Objects.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">The following example illustrates a version check:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>const VERSION: u64 = 1;\n\nstruct Pool has key {\n    id: UID,\n    version: u64,\n    \u002F\u002F ... other fields\n}\n\npublic fun swap(pool: &amp;mut Pool, ...) {\n    assert!(pool.version == VERSION, E_WRONG_VERSION);\n    \u002F\u002F ... swap logic\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp class=\"docx-align-justify\">When publishing a new version, the module&#39;s \u003Ccode>VERSION\u003C\u002Fcode> can be increased to 2, with a migration function protected by an appropriate capability:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>const VERSION: u64 = 2;\n\npublic fun migrate(pool: &amp;mut Pool, _: &amp;AdminCap) {\n    assert!(pool.version == 1, E_WRONG_VERSION);\n    pool.version = 2;\n    \u002F\u002F ... migrate state if needed\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp class=\"docx-align-justify\">These snippets illustrate the mechanism rather than provide a complete implementation. Production code must account for the actual module types, authorization rules, and migration requirements. Passing an \u003Ccode>AdminCap\u003C\u002Fcode> illustrates how a capability object can restrict migration privileges.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">After migration, the Pool&#39;s version becomes 2. A legacy function will abort on a version mismatch only if that version already checks \u003Ccode>pool.version == VERSION\u003C\u002Fcode> at the relevant entry points.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">\u003Cstrong>The critical limitation is that adding a version check to the new Package cannot change the behavior of legacy code that never implemented one.\u003C\u002Fstrong> If V1 lacks the check, adding it to V2 does not disable V1.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">Sui also imposes struct-layout compatibility requirements on upgrades. Developers cannot assume that arbitrary fields can be added to an already published struct. Version fields and migration mechanisms should therefore be considered during the initial design.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">\u003Cstrong>Reference:\u003C\u002Fstrong> \u003Ca href=\"https:\u002F\u002Fdocs.sui.io\u002Fconcepts\u002Fsui-move-concepts\u002Fpackages\u002Fupgrade\" rel=\"nofollow\">Sui Documentation: Upgrading Packages\u003C\u002Fa>\u003C\u002Fp>\n\u003Ch3>6.2 Approach Two: Introduce a New Object Type When Legacy Code Lacks Version Checks\u003C\u002Fh3>\n\u003Cp class=\"docx-align-justify\">If a deployed legacy version lacks version checks and its behavior cannot be changed through a compatible upgrade, the protocol may need to introduce a new object type and migrate the state into it.\u003C\u002Fp>\n\u003Cpre>\u003Ccode>struct PoolV2 has key {\n    id: UID,\n    \u002F\u002F ... new fields with correct accounting\n}\n\npublic fun migrate_to_v2(old_pool: Pool, _: &amp;AdminCap): PoolV2 {\n    \u002F\u002F Transfer assets, validate balances\n    \u002F\u002F Return new PoolV2\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp class=\"docx-align-justify\">The migration process should:\u003C\u002Fp>\n\u003Col>\n\u003Cli>Verify authorization through a protected administrative entry point.\u003C\u002Fli>\n\u003Cli>Transfer assets and required state from the legacy object to the new \u003Ccode>PoolV2\u003C\u002Fcode> object.\u003C\u002Fli>\n\u003Cli>Validate balances, reserves, and LP supply before and after migration.\u003C\u002Fli>\n\u003Cli>Emit migration events recording the relationship between the old and new objects.\u003C\u002Fli>\n\u003Cli>Update routers, SDKs, and other dependencies to use the new object.\u003C\u002Fli>\n\u003Cli>Deprecate the old object and prevent it from being used in normal protocol operations.\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp class=\"docx-align-justify\">Creating \u003Ccode>PoolV2\u003C\u002Fcode> alone does not disable the old Package. The protocol must verify that legacy execution paths cannot affect the new authoritative state or leave users exposed to obsolete asset-handling functions.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">Sui&#39;s upgrade documentation discusses introducing new types and migration functions when legacy Shared Objects contain flawed logic. The new implementation can then accept only the new object type, breaking the compatibility relationship with the legacy object.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">Effective remediation must address Package versions, object types, state migration, and dependent callers together. Adding access controls to the latest version does not change the behavior of historical Packages.\u003C\u002Fp>\n\u003Chr>\n\u003Ch2>7. Regression Testing: Verifying the Cross-Version Fix\u003C\u002Fh2>\n\u003Cp class=\"docx-align-justify\">Testing should cover interactions between Package versions, not just the latest implementation. The goal is to verify that legacy execution paths cannot violate the protocol&#39;s state invariants.\u003C\u002Fp>\n\u003Ch3>7.1 Ensure Legacy Functions Cannot Operate on Migrated Objects\u003C\u002Fh3>\n\u003Cp class=\"docx-align-justify\">If object version checks are used, test the expected behavior:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>Given:\n    Pool.version = 2\n    V1.VERSION = 1\n\nWhen:\n    V1.swap(Pool)\n\nThen:\n    Transaction aborts with E_WRONG_VERSION\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp class=\"docx-align-justify\">This test is valid only if V1 already contains the version check. Testing V2 alone cannot prove that legacy code without such a check has been blocked.\u003C\u002Fp>\n\u003Ch3>7.2 Test Cross-Version Call Sequences\u003C\u002Fh3>\n\u003Cp class=\"docx-align-justify\">Test combinations such as:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Ccode>V1.swap\u003C\u002Fcode> → \u003Ccode>V2.add_liquidity\u003C\u002Fcode>\u003C\u002Fli>\n\u003Cli>\u003Ccode>V2.swap\u003C\u002Fcode> → \u003Ccode>V1.remove_liquidity\u003C\u002Fcode>\u003C\u002Fli>\n\u003Cli>\u003Ccode>V1.update\u003C\u002Fcode> → \u003Ccode>V2.mint\u003C\u002Fcode>\u003C\u002Fli>\n\u003Cli>\u003Ccode>V2.migrate\u003C\u002Fcode> → \u003Ccode>V1.swap\u003C\u002Fcode>\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp class=\"docx-align-justify\">Operations that are prohibited by design should abort or fail because of type isolation. Permitted combinations must preserve consistent asset balances, reserves, and LP supply.\u003C\u002Fp>\n\u003Ch3>7.3 Verify LP Minting Against Actual Deposits\u003C\u002Fh3>\n\u003Cp class=\"docx-align-justify\">Construct a test state similar to the one described in the BlueMove analysis:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>Escrow balance = 350,000 SUI\nPool balance   =   7,022 SUI\nreserve_x      =   7,022 SUI\nLP supply      =   1,000\nDeposit        =       0.057 SUI\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp class=\"docx-align-justify\">When \u003Ccode>reserve_x\u003C\u002Fcode> differs from the authoritative reserve, the protocol should reject unsafe minting or ensure that historical balance differences cannot be counted as newly deposited assets.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">Tests should verify the resulting LP amount against the actual deposit and the correct reserve baseline, rather than checking only whether the function executes successfully.\u003C\u002Fp>\n\u003Ch3>7.4 Verify Invariants Before and After Migration\u003C\u002Fh3>\n\u003Cp class=\"docx-align-justify\">For an AMM, regression tests should cover:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Actual asset balances held by the Pool and Escrow.\u003C\u002Fli>\n\u003Cli>Consistency between \u003Ccode>reserve_x\u003C\u002Fcode>, \u003Ccode>reserve_y\u003C\u002Fcode>, and the authoritative asset storage.\u003C\u002Fli>\n\u003Cli>Total LP supply and withdrawal proportions.\u003C\u002Fli>\n\u003Cli>Authorization requirements for migration functions.\u003C\u002Fli>\n\u003Cli>Potential asset loss or duplicate accounting if migration fails.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp class=\"docx-align-justify\">Tests should include successful and repeated migrations, unauthorized calls, residual legacy objects, and attempts to invoke legacy code after migration.\u003C\u002Fp>\n\u003Chr>\n\u003Ch2>8. Conclusion: Upgrade Security Must Cover Every Still-Callable Code Path\u003C\u002Fh2>\n\u003Cp class=\"docx-align-justify\">Sui&#39;s immutable Package model allows protocols to evolve while preserving historical code. When multiple versions can still access the same Shared Object, changes to storage structures, reserve calculations, and business rules can leave those versions operating against inconsistent state assumptions.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">Addressing this risk requires coordinated Package version management, Shared Object version checks, legacy-object migration, dependency updates, and cross-version regression testing. True upgrade security means verifying that every still-callable Package version preserves the same set of state invariants.\u003C\u002Fp>\n\n\n\u003Cp class=\"docx-align-justify\">BitsLab is a Web3 security company focused on smart contract auditing and security infrastructure for emerging blockchain ecosystems, including Sui, Aptos, Bitcoin, and TON. MoveBit, a flagship sub-brand of BitsLab, specializes in Move ecosystem security, providing smart contract audits and security research for projects building on Sui, Aptos, and other Move-based platforms.\u003C\u002Fp>\n\u003Ch3>Related Resources\u003C\u002Fh3>\n\u003Cp class=\"docx-align-justify\">\u003Cstrong>Sui Official Documentation\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Ca href=\"https:\u002F\u002Fdocs.sui.io\u002Fconcepts\u002Fsui-move-concepts\u002Fpackages\u002Fupgrade\" rel=\"nofollow\">Upgrading Packages\u003C\u002Fa>\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"https:\u002F\u002Fdocs.sui.io\u002Fconcepts\u002Fsui-move-concepts\u002Fpackages\u002Fupgrade\" rel=\"nofollow\">Package Versioning\u003C\u002Fa>\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"https:\u002F\u002Fdocs.sui.io\u002Fguides\u002Fdeveloper\u002Fsui-101\u002Fsecurity\" rel=\"nofollow\">Security Best Practices\u003C\u002Fa>\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp class=\"docx-align-justify\">\u003Cstrong>MoveBit Research\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Ca href=\"https:\u002F\u002Fx.com\u002FMoveBit_\u002Fstatus\u002F2109486777723748495\" rel=\"nofollow\">Sui Shared Object Security: How Access Control Flaws Put DeFi Protocols at Risk\u003C\u002Fa>\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"https:\u002F\u002Fforums.sui.io\u002Ft\u002Fbluemove-was-not-an-overflow-bug-how-a-cross-version-reserve-desync-drained-714-000-sui\u002F49409\" rel=\"nofollow\">BlueMove Cross-Version Reserve Desynchronization Analysis\u003C\u002Fa>\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp class=\"docx-align-justify\">\u003Cstrong>Official Websites\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Ca href=\"https:\u002F\u002Fmovebit.xyz\u002F\" rel=\"nofollow\">MoveBit\u003C\u002Fa>\u003C\u002Fli>\n\u003Cli>\u003Ca href=\"https:\u002F\u002Fwww.bitslab.xyz\u002F\" rel=\"nofollow\">BitsLab\u003C\u002Fa>\u003C\u002Fli>\n\u003C\u002Ful>","\u002Fmedia\u002Fmovebit\u002F2026\u002F10\u002Fc694b8c5b203afefafc2aefa5bd1a5c1.png","2026-10-22T02:22:49Z","2026-10-22T10:22:49Z","15 min read",true,"Sui Move Security: Why Legacy Packages Can Still Put Shared Objects at Risk After an Upgrade cover image",{"slug":29,"category":7,"categoryLabel":6,"subcategoryLabel":17,"authorName":30,"title":31,"excerpt":32,"contentHtml":33,"coverUrl":34,"publishedAt":35,"updatedAt":36,"readTime":25,"cover":34,"hasCover":26,"coverAlt":37},"sui-shared-object-security-how-access-control-flaws-put-defi-protocols-at-risk-9dc56b","Olivia","Sui Shared Object Security: How Access Control Flaws Put DeFi Protocols at Risk","As an increasing number of DeFi protocols deploy on Sui, Shared Objects have become essential components of liquidity pools, lending markets, and other on-chain financial applications. However, a seemingly simple permission issue can expose an entire protocol's risk parameters to unauthorized calls.","\u003Cp class=\"docx-align-justify\">As an increasing number of DeFi protocols deploy on Sui, Shared Objects have become essential components of liquidity pools, lending markets, and other on-chain financial applications. However, a seemingly simple permission issue can expose an entire protocol&#39;s risk parameters to unauthorized calls.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">Suppose a Sui lending protocol stores its liquidation threshold inside a shared \u003Ccode>Market\u003C\u002Fcode> object. Regular users need to access this \u003Ccode>Market\u003C\u002Fcode> object to make deposits, borrows, and repayments, while administrators are responsible for adjusting risk configurations like collateral ratios and liquidation thresholds.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">Now, what happens if a regular user can modify the liquidation threshold through a public function?\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">An attacker might not need to compromise an administrator account or bypass Move VM security mechanisms. They only need to find a state-modification path lacking proper authorization checks to alter critical protocol parameters, directly impacting the liquidation conditions of existing positions.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">This represents a key class of issues worth studying in Sui Shared Object Security.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">Sui Move provides strong foundational security guarantees through Object Ownership, resource models, and type systems. However, these mechanisms do not automatically determine whether every business operation aligns with a protocol’s intended permission design.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">For DeFi protocols containing multiple Pools, Vaults, and Markets, developers must manage even more complex object relationships, Capability scopes, and state transition rules.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">In MoveBit&#39;s (a flagship sub-brand of BitsLab) Sui security research, access control for Shared Objects is a critical direction during security audits. This article uses a simplified lending market case study to analyze how missing access checks create vulnerabilities, what issues can arise in Capability design, and how to verify these risks through testing and security audits.\u003C\u002Fp>\n\u003Chr>\n\u003Ch2>1. Why Do Shared Objects Require Dedicated Access Control Considerations?\u003C\u002Fh2>\n\u003Cp class=\"docx-align-justify\">Sui utilizes an Object Model to manage on-chain state. Every object possesses a unique identifier, ownership metadata, and versioning. Protocols choose different object ownership models based on operational needs.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">Common ownership forms include \u003Cstrong>Address-Owned Objects\u003C\u002Fstrong>, \u003Cstrong>Immutable Objects\u003C\u002Fstrong>, and \u003Cstrong>Shared Objects\u003C\u002Fstrong>.\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>Address-Owned Objects:\u003C\u002Fstrong> Transaction usage rights are constrained by explicit object ownership.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Immutable Objects:\u003C\u002Fstrong> Can be publicly read by anyone but cannot be modified.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Shared Objects:\u003C\u002Fstrong> Allow different users to concurrently reference the same object within transactions and execute operations defined by the Move contract logic governing that object.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp class=\"docx-align-justify\">Sui&#39;s official documentation explicitly states that any address can submit a transaction referencing a Shared Object; therefore, when privileged operations are involved, the contract itself must execute the corresponding authorization checks.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">For DeFi applications, shared access brings clear operational value.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">For example, an AMM protocol can use a Shared Object to store liquidity pool reserves, fee configurations, and protocol parameters. Different users can execute transaction functions to interact with the exact same Pool.\u003C\u002Fp>\n\u003Cpre>\u003Ccode>LiquidityPool\n├── Token A Reserve\n├── Token B Reserve\n├── Trading Fee\n└── Protocol Configuration\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp class=\"docx-align-justify\">When regular users perform a swap, asset balances within the pool are updated according to protocol rules. However, modifying trading fees, updating pause states, or altering key configurations usually constitute restricted operations.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">While both types of operations may utilize \u003Ccode>&amp;mut LiquidityPool\u003C\u002Fcode>, the authorization requirements they must satisfy are fundamentally different.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">In Sui Move, \u003Ccode>&amp;mut T\u003C\u002Fcode> allows a function to modify data of type \u003Ccode>T\u003C\u002Fcode>, provided it satisfies type and borrowing rules. It does not natively provide admin authentication, nor does it confer arbitrary capabilities upon the caller to modify object fields. Which specific modifications can be executed remains entirely dictated by the module defining the object type and its public functions.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">Consequently, security analysis of Shared Objects must look deep into function implementations and authorization relationships between objects.\u003C\u002Fp>\n\u003Chr>\n\u003Ch2>2. What Risks Does an Access-Control-Deficient Market Function Present?\u003C\u002Fh2>\n\u003Cp class=\"docx-align-justify\">Consider a simplified Sui lending market where the protocol utilizes a shared \u003Ccode>Market\u003C\u002Fcode> object to store liquidation thresholds and other risk parameters:\u003C\u002Fp>\u003Cp class=\"docx-align-justify\">\u003Cimg src=\"\u002Fmedia\u002Fmovebit\u002F2026\u002F10\u002Fdfd888addf58981b79efc87f2ff0f586.png\" width=\"300\">\u003Cbr>\u003C\u002Fp>\n\n\u003Cp class=\"docx-align-justify\">Under normal conditions, regular users access \u003Ccode>Market\u003C\u002Fcode> to perform borrowing and lending operations, while \u003Ccode>liquidation_threshold\u003C\u002Fcode> should only be modifiable by authorized administrators or governance mechanisms.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">Suppose a developer implements the following function:\u003C\u002Fp>\u003Cp class=\"docx-align-justify\">\u003Cimg src=\"\u002Fmedia\u002Fmovebit\u002F2026\u002F10\u002F829dad6b4d0263aefe6414a8a39ceda0.png\" width=\"300\">\u003Cbr>\u003C\u002Fp>\n\n\u003Cp class=\"docx-align-justify\">This code successfully passes basic type checks and indeed modifies the \u003Ccode>Market\u003C\u002Fcode>&#39;s liquidation threshold.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">The critical issue is that \u003Cstrong>this function contains no authorization checks whatsoever\u003C\u002Fstrong>.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">A \u003Ccode>public\u003C\u002Fcode> function can be accessed via permitted cross-module calls or Programmable Transaction Block (PTB) invocation paths. If a shared \u003Ccode>Market\u003C\u002Fcode> can be passed as a transaction input, an attacker can supply a mutable reference to the shared \u003Ccode>Market\u003C\u002Fcode> along with an arbitrary \u003Ccode>new_threshold\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">No Move resource safety rules are violated here. The attacker simply uses a legitimately referenced shared object to execute a publicly exposed protocol operation.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">Assuming the liquidation threshold uses basis points with an initial value of \u003Ccode>8,000\u003C\u002Fcode> (80%), if an attacker modifies it to \u003Ccode>9,900\u003C\u002Fcode> or another abnormal value, the market&#39;s liquidation conditions will diverge completely from the original design.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">The exact consequences depend on the protocol&#39;s parameter validation ranges, health factor calculation methods, and liquidation execution logic. Certain implementations could render high-risk positions temporarily unliquidatable, while others might cause healthy positions to suffer abnormal liquidations.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">For this specific example, the confirmed flaw is clear: \u003Cstrong>an unauthorized user can modify critical risk parameters that should have been strictly protected.\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">Whether actual financial losses occur depends on further analysis of the protocol&#39;s business logic and economic parameters.\u003C\u002Fp>\n\u003Chr>\n\u003Ch2>3. How to Reproduce and Verify This Attack Path\u003C\u002Fh2>\n\u003Cp class=\"docx-align-justify\">When conducting a security analysis on this example, auditors can start with the \u003Ccode>liquidation_threshold\u003C\u002Fcode> field:\u003C\u002Fp>\n\u003Col>\n\u003Cli>Confirm where it is initialized.\u003C\u002Fli>\n\u003Cli>Determine which functions read its value.\u003C\u002Fli>\n\u003Cli>Check if alternative modification paths exist.\u003C\u002Fli>\n\u003Cli>Inspect the visibility and parameters of writing functions to verify if regular users can construct the required object inputs.\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp class=\"docx-align-justify\">For the \u003Ccode>update_threshold()\u003C\u002Fcode> function shown above, the potential execution path is direct:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>Attacker Transaction\n        ↓\nShared Market Object\n        ↓\nPublic update_threshold()\n        ↓\nNo Authorization Check\n        ↓\nliquidation_threshold Modified\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp class=\"docx-align-justify\">Throughout this invocation flow, the function does not request an \u003Ccode>AdminCap\u003C\u002Fcode>, nor does it verify caller identity or any authorization conditions.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">To further verify the vulnerability, developers can use Sui&#39;s official \u003Ccode>test_scenario\u003C\u002Fcode> framework to simulate different transaction senders.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">For instance, Account A creates the \u003Ccode>Market\u003C\u002Fcode> and sets it as a Shared Object. Then, the test switches to Account B (which lacks administrative permissions), and Account B attempts to modify the liquidation threshold via the public function.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">The following code demonstrates the key testing logic:\u003C\u002Fp>\u003Cp class=\"docx-align-justify\">\u003Cimg src=\"\u002Fmedia\u002Fmovebit\u002F2026\u002F10\u002Fc616261635a38f93db7ce987cc33e74a.png\" width=\"300\">\u003Cbr>\u003C\u002Fp>\n\n\u003Cblockquote>\n\u003Cp class=\"docx-align-justify\">\u003Cstrong>Code Note:\u003C\u002Fstrong> \u003Cem>This test is for instructional purposes, assuming \u003Ccode>create_market()\u003C\u002Fcode> is already implemented in the test package and correctly creates a Shared Market. It demonstrates the vulnerability verification concept and has not been independently compiled.\u003C\u002Fem>\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Cp class=\"docx-align-justify\">In actual testing, if an unauthorized account successfully executes the call and the \u003Ccode>Market\u003C\u002Fcode>&#39;s liquidation threshold is altered upon transaction completion, the unauthorized state modification path is proven to exist.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">Next, auditors must evaluate whether this parameter change impacts borrowing limits, position health, or liquidation outcomes. Only by completing business-level validations can the severity and exploitability of the vulnerability be accurately gauged.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">In complex protocols, attack paths might span multiple public functions and modules. For instance, a function might not directly modify the liquidation threshold, but could achieve the same result by updating configuration objects, swapping dependent objects, or invoking functions in other modules.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">Therefore, security audits must trace the complete \u003Cstrong>State Transition\u003C\u002Fstrong> path to ensure every path capable of modifying sensitive state is protected by proper authorization.\u003C\u002Fp>\n\u003Chr>\n\u003Ch2>4. How to Fix Access Control Issues Using the Capability Pattern\u003C\u002Fh2>\n\u003Cp class=\"docx-align-justify\">Sui Move typically manages privileged operations using the \u003Cstrong>Capability Pattern\u003C\u002Fstrong>.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">A Capability is an object that represents permission to execute a specific operation. Functions restrict sensitive operations by requiring callers to provide a reference to a specific Capability object.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">For our lending market example, we can create an \u003Ccode>AdminCap\u003C\u002Fcode> corresponding to each \u003Ccode>Market\u003C\u002Fcode>, storing the target \u003Ccode>Market\u003C\u002Fcode>&#39;s \u003Ccode>ID\u003C\u002Fcode> inside the Capability itself.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">Below is a simplified remediation implementation:\u003C\u002Fp>\u003Cp class=\"docx-align-justify\">\u003Cimg src=\"\u002Fmedia\u002Fmovebit\u002F2026\u002F10\u002F123edbda76c1a22684eb22a59917dd7e.png\" width=\"300\">\u003Cbr>\u003C\u002Fp>\n\n\u003Cblockquote>\n\u003Cp class=\"docx-align-justify\">\u003Cstrong>Code Note:\u003C\u002Fstrong> \u003Cem>This example demonstrates object-level authorization core implementation and excludes real lending, liquidation, governance, or permission revocation modules. \u003Ccode>create_market()\u003C\u002Fcode> is designed to allow users to create independent demo markets and does not imply production lending protocols should adopt permissionless market creation. This code has not been independently compiled.\u003C\u002Fem>\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Cp class=\"docx-align-justify\">Compared to the vulnerable version, the updated \u003Ccode>update_threshold()\u003C\u002Fcode> function introduces three critical constraints:\u003C\u002Fp>\n\u003Col>\n\u003Cli>\u003Cstrong>Requires \u003Ccode>&amp;AdminCap\u003C\u002Fcode>:\u003C\u002Fstrong> When the Capability employs proper Address-Owned ownership, Sui&#39;s object ownership model restricts who can pass it as a transaction input.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Validates Market Binding:\u003C\u002Fstrong> \u003Ccode>admin.market_id == object::id(market)\u003C\u002Fcode> verifies the explicit link between the Capability and the \u003Ccode>Market\u003C\u002Fcode>. Even if a caller possesses a valid \u003Ccode>AdminCap\u003C\u002Fcode>, they cannot use it to modify a different \u003Ccode>Market\u003C\u002Fcode>.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Validates Bounds &amp; Emits Events:\u003C\u002Fstrong> Checks the bounds of \u003Ccode>new_threshold\u003C\u002Fcode> and emits a \u003Ccode>ThresholdUpdated\u003C\u002Fcode> event upon success to facilitate off-chain tracking of parameter changes.\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cblockquote>\n\u003Cp class=\"docx-align-justify\">\u003Cstrong>Crucial Requirement:\u003C\u002Fstrong> During remediation, legacy public functions lacking permission checks \u003Cstrong>must be removed or restricted\u003C\u002Fstrong>. Retaining legacy entry points allows attackers to continue modifying fields through unprotected paths.\u003C\u002Fp>\n\u003C\u002Fblockquote>\n\u003Chr>\n\u003Ch3>Key Considerations for Capability Design\u003C\u002Fh3>\n\u003Ch4>1. Ownership of the Capability Itself\u003C\u002Fh4>\n\u003Cp class=\"docx-align-justify\">Suppose a protocol mistakenly sets an \u003Ccode>AdminCap\u003C\u002Fcode> as a Shared Object. If any user can pass references to this shared Capability into privileged functions, the requirement for \u003Ccode>&amp;AdminCap\u003C\u002Fcode> fails to enforce admin access controls.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">A Capability&#39;s effectiveness depends entirely on its type, ownership model, and usage restrictions enforced within contract logic. Permissions meant for a single administrator or governance body must use controlled ownership or vault structures to prevent unauthorized access.\u003C\u002Fp>\n\u003Ch4>2. Association Between Capability and Target Objects\u003C\u002Fh4>\n\u003Cp class=\"docx-align-justify\">In multi-market, multi-pool, or multi-vault protocols, verifying the Capability type alone is insufficient.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">If \u003Ccode>Market A\u003C\u002Fcode> and \u003Ccode>Market B\u003C\u002Fcode> both accept the same \u003Ccode>AdminCap\u003C\u002Fcode> type without ID validation, a user holding management rights over \u003Ccode>Market A\u003C\u002Fcode> could illegally manage \u003Ccode>Market B\u003C\u002Fcode>. Binding \u003Ccode>market_id\u003C\u002Fcode> as shown in the example provides baseline protection against cross-object unauthorized calls.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">Production protocols should also validate Capability versions, protocol instance IDs, permission roles, and governance states.\u003C\u002Fp>\n\u003Ch4>3. Creation, Transfer, and Revocation Lifecycle\u003C\u002Fh4>\n\u003Cp class=\"docx-align-justify\">Once created, a Capability becomes a critical asset within a protocol&#39;s privilege architecture.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">Audits must confirm that Capabilities cannot be duplicated, misallocated, accidentally transferred, or retained after admin handovers.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">When permissions are compromised, protocols must be capable of rejecting compromised Capabilities. Recommended Sui practices include:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Valid Capability ID registries\u003C\u002Fli>\n\u003Cli>Version control\u003C\u002Fli>\n\u003Cli>Epoch-based expiration checks\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp class=\"docx-align-justify\">Relying solely on compromised holders to voluntarily destroy capabilities is insufficient for revocation.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">Additionally, if a protocol supports upgrades, auditors must review \u003Ccode>UpgradeCap\u003C\u002Fcode> holders and upgrade policies. Even if current implementations enforce strict checks, future code upgrades could alter these rules.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">Capability security must cover the complete lifecycle: \u003Cstrong>Creation $\\rightarrow$ Possession $\\rightarrow$ Usage $\\rightarrow$ Transfer $\\rightarrow$ Revocation $\\rightarrow$ Upgrade.\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Chr>\n\u003Ch2>5. How to Verify That Fixes Are Effective\u003C\u002Fh2>\n\u003Cp class=\"docx-align-justify\">After introducing Capability checks, security tests must be updated accordingly:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>Positive Validation:\u003C\u002Fstrong> Authorized administrators can successfully modify their assigned \u003Ccode>Market\u003C\u002Fcode>.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Negative Validation:\u003C\u002Fstrong> Unauthorized users fail when attempting the same operations.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Cross-Capability Testing:\u003C\u002Fstrong> Multi-market protocols must test scenarios involving mismatched Capabilities (e.g., attempting to update \u003Ccode>Market A\u003C\u002Fcode> using \u003Ccode>Market B\u003C\u002Fcode>&#39;s \u003Ccode>AdminCap\u003C\u002Fcode>).\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp class=\"docx-align-justify\">Under the updated logic, mismatched operations must fail due to Object ID validation errors. The core test assertion is:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>assert!(\n    admin.market_id == object::id(market),\n    EWrongMarket\n);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp class=\"docx-align-justify\">In unit tests, developers can use \u003Ccode>#[expected_failure]\u003C\u002Fcode> to confirm that \u003Ccode>EWrongMarket\u003C\u002Fcode> is raised as intended.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">It is important to distinguish between two failure types:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Cstrong>Logic Failure:\u003C\u002Fstrong> Supplying a valid Capability belonging to another \u003Ccode>Market\u003C\u002Fcode> triggers contract-internal assertion failures.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Ownership Failure:\u003C\u002Fstrong> Failing to possess an Address-Owned \u003Ccode>AdminCap\u003C\u002Fcode> causes rejection during Sui transaction input validation before Move function execution starts.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp class=\"docx-align-justify\">Both failure types require testing, though their verification methods differ.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">Additionally, development teams must audit all functions capable of writing to \u003Ccode>liquidation_threshold\u003C\u002Fcode>. If \u003Ccode>update_threshold()\u003C\u002Fcode> is secured but a public \u003Ccode>update_config()\u003C\u002Fcode> function still allows unrestricted modifications to the same field, the risk remains unresolved.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">For production lending protocols, verification should span three levels:\u003C\u002Fp>\n\u003Col>\n\u003Cli>\u003Cstrong>Permission Testing:\u003C\u002Fstrong> Ensure every sensitive operation has explicit authorization checks, and test mismatched objects, cross-instance Capabilities, and alternative invocation paths.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Parameter Constraint Testing:\u003C\u002Fstrong> Validate that risk parameters (liquidation thresholds, fees, collateral ratios) can only be modified within strictly defined ranges.\u003C\u002Fli>\n\u003Cli>\u003Cstrong>Protocol Behavior Testing:\u003C\u002Fstrong> Verify that post-modification borrow, repayment, and liquidation operations adhere to expected economic constraints.\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp class=\"docx-align-justify\">Sui&#39;s CLI tool supports running unit tests via \u003Ccode>sui move test\u003C\u002Fcode>, while \u003Ccode>test_scenario\u003C\u002Fcode> enables simulation of multi-sender transactions, object transfers, and shared object interactions:\u003C\u002Fp>\n\u003Cpre>\u003Ccode>sui move test\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp class=\"docx-align-justify\">Prior to mainnet deployment, protocols should validate operations across local networks, Testnet, and real transaction constructs to ensure contract logic behaves as expected within the live Sui execution environment.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">For production protocols, comprehensive confidence in remediation effectiveness requires code reviews, permission testing, and business logic verification working in unison across all critical state transitions.\u003C\u002Fp>\n\u003Chr>\n\u003Ch2>6. How MoveBit Analyzes Permission Risks in Complex Sui Protocols\u003C\u002Fh2>\n\u003Cp class=\"docx-align-justify\">The previous example featured a single \u003Ccode>Market\u003C\u002Fcode> and one \u003Ccode>AdminCap\u003C\u002Fcode>, making attack paths straightforward to trace. However, real-world Sui DeFi protocols feature far more complex object topologies.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">A lending market may simultaneously depend on \u003Ccode>Pool\u003C\u002Fcode>, \u003Ccode>Vault\u003C\u002Fcode>, \u003Ccode>Position\u003C\u002Fcode>, \u003Ccode>Oracle\u003C\u002Fcode>, \u003Ccode>Treasury\u003C\u002Fcode>, and \u003Ccode>Governance\u003C\u002Fcode> objects. Logic is distributed across multiple modules, with state managed dynamically via Dynamic Fields.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">In these environments, simply checking if a function accepts an \u003Ccode>AdminCap\u003C\u002Fcode> parameter is insufficient to assess overall authorization security.\u003C\u002Fp>\n\u003Ch3>1. Starting from Object Relationships\u003C\u002Fh3>\n\u003Cp class=\"docx-align-justify\">MoveBit&#39;s \u003Cstrong>Sui Smart Contract Audit\u003C\u002Fstrong> builds state and authorization maps around a protocol&#39;s Object Model to identify:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Shared objects vs. private objects.\u003C\u002Fli>\n\u003Cli>Objects holding critical assets or risk configurations.\u003C\u002Fli>\n\u003Cli>Mappings between Capabilities and target objects.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp class=\"docx-align-justify\">For example, a lending liquidation process involves user \u003Ccode>Position\u003C\u002Fcode>s, shared \u003Ccode>Market\u003C\u002Fcode>s, \u003Ccode>Oracle\u003C\u002Fcode> prices, and liquidation parameters. Auditors verify that these objects belong to the expected protocol instance, check for cross-market object mixing, and ensure states cannot be modified through unauthorized calls.\u003C\u002Fp>\n\u003Ch3>2. Tracing Authorization Logic Along Execution Paths\u003C\u002Fh3>\n\u003Cp class=\"docx-align-justify\">The second step involves mapping all public functions capable of modifying sensitive fields alongside their invocation hierarchies.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">For \u003Ccode>Market.liquidation_threshold\u003C\u002Fcode>, auditors identify every potential write path and evaluate its authorization controls. If a function relies on \u003Ccode>tx_context::sender()\u003C\u002Fcode>, auditors check whether business rules strictly require transaction-sender-based checks. Where permissions are represented via Capabilities, governance objects, or escrow patterns, auditors evaluate ownership conditions and authorization boundaries.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">In protocols with extensive cross-module interactions, special focus is placed on ensuring permissions are not improperly forwarded, escalated, or reused.\u003C\u002Fp>\n\u003Ch3>3. Combining State Transition Analysis with Practical Verification\u003C\u002Fh3>\n\u003Cp class=\"docx-align-justify\">Final risk determinations rest on state modification outcomes:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Can an execution path successfully alter the liquidation threshold?\u003C\u002Fli>\n\u003Cli>Does the modified parameter impact active positions?\u003C\u002Fli>\n\u003Cli>Can an attacker leverage the modified state to execute unauthorized borrows, withdrawals, or liquidations?\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp class=\"docx-align-justify\">Answering these questions requires analyzing code execution paths, object relationships, and business logic while verifying findings through concrete PoC tests.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">For large-scale Move protocols with complex object relationships, AI-assisted analysis can provide valuable support.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">BitsLab developed \u003Cstrong>BitsLab AI\u003C\u002Fstrong>, focusing on \u003Cem>Logic Reasoning\u003C\u002Fem>, \u003Cem>Evidence Chains\u003C\u002Fem>, and \u003Cem>PoC Verification\u003C\u002Fem>. It combines code logic understanding, risk path analysis, and vulnerability verification.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">Starting from sensitive state fields, it traces related functions and permission checks, flags potential unauthorized modification paths, and uses automated testing to confirm exploitability.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">This methodology helps auditors systematically organize suspicious paths and verification evidence. While AI provides analytical leads for complex cross-module and multi-object interactions, final conclusions must always be verified against Sui Object Ownership rules, Capability holding conditions, and Move VM execution mechanics.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">MoveBit brings extensive security experience across the Sui ecosystem. In Sui&#39;s June 2025 ecosystem security review, \u003Cem>&#34;Greater Ecosystem Security Through Audits and Move Registry&#34;\u003C\u002Fem>, MoveBit was recognized as a key security audit firm within the Sui ecosystem, with special mention of its contributions to formal verification, developer tooling, and security competitions.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">MoveBit&#39;s public audit portfolio includes leading Sui ecosystem projects such as \u003Cstrong>Scallop\u003C\u002Fstrong>, \u003Cstrong>Cetus\u003C\u002Fstrong>, and \u003Cstrong>NAVI Protocol\u003C\u002Fstrong>. These public audit reports help development teams understand real-world audit scopes, code versions, issue classifications, and fix verification processes.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">For complex Sui DeFi applications, security audits must evaluate object ownership, permission design, state transitions, and business rules within a unified execution context to accurately identify potential risks.\u003C\u002Fp>\n\u003Chr>\n\u003Ch2>7. Shared Object Security Must Cover the Entire Protocol Lifecycle\u003C\u002Fh2>\n\u003Cp class=\"docx-align-justify\">Shared Object permission issues must be addressed before protocol deployment.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">In lending, trading, and yield protocols, critical states undergo continuous evolution. Projects frequently add new Markets, adjust risk parameters, switch Oracles, or introduce new business modules via Package Upgrades.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">These changes can alter existing authorization dynamics:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Does an \u003Ccode>AdminCap\u003C\u002Fcode> designed for a single market maintain appropriate permission boundaries as the protocol expands?\u003C\u002Fli>\n\u003Cli>Do newly added configuration functions reuse legacy permission checks correctly?\u003C\u002Fli>\n\u003Cli>Does a package upgrade introduce new invocation paths capable of modifying sensitive state?\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp class=\"docx-align-justify\">Every upgrade impacting permissions or critical state requires thorough re-verification.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">Sui&#39;s official security guidelines emphasize that smart contract audits must evaluate specific code versions, dependencies, and upgrade authorities. For upgradeable protocols, security guarantees from an earlier audit do not automatically extend to future code modifications.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">Consequently, teams must establish continuous security review processes, complemented by traceable events and monitoring rules for parameter updates and admin operations.\u003C\u002Fp>\n\u003Chr>\n\u003Ch2>Conclusion &amp; Next Steps\u003C\u002Fh2>\n\u003Cp class=\"docx-align-justify\">For teams building or upgrading Sui DeFi protocols involving Shared Pools, Markets, Vaults, or complex Capability designs, conducting a comprehensive audit of object relationships, permission checks, and state transitions prior to deployment is highly recommended.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">\u003Cstrong>MoveBit\u003C\u002Fstrong> provides specialized \u003Cstrong>Smart Contract Security Audits\u003C\u002Fstrong> for Sui and Move ecosystem projects, focusing on object ownership, permission logic, state transitions, and protocol business risks to help teams identify and remediate potential security flaws before mainnet deployment.\u003C\u002Fp>\n\u003Cp class=\"docx-align-justify\">If your project is preparing for deployment, upgrading smart contracts, or re-evaluating audit requirements, reach out via the official MoveBit website to discuss your code scope, protocol architecture, and security review needs.\u003C\u002Fp>\u003Ch2>\u003Cspan>Related Resources\u003C\u002Fspan>\u003C\u002Fh2>\u003Ch3>\u003Cspan>Sui Official Documentation\u003C\u002Fspan>\u003C\u002Fh3>\u003Cul>\u003Cli>\u003Cp>\u003Ca href=\"https:\u002F\u002Fdocs.sui.io\u002Fdevelop\u002Fwrite-move\u002Fmove-best-practices?utm_source=chatgpt.com\" rel=\"nofollow\">\u003Cspan>Move Best Practices\u003C\u002Fspan>\u003C\u002Fa>\u003Cbr>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Ca href=\"https:\u002F\u002Fwww.sui.io\u002Fblog\u002Fsecurity-best-practices?utm_source=chatgpt.com\" rel=\"nofollow\">\u003Cspan>Security Best Practices for Building on Sui\u003C\u002Fspan>\u003C\u002Fa>\u003Cbr>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Ca href=\"https:\u002F\u002Fdocs.sui.io\u002Fdevelop\u002Fobjects\u002Fobject-ownership\u002Fshared\" rel=\"nofollow\">\u003Cspan>Shared Objects Documentation\u003C\u002Fspan>\u003C\u002Fa>\u003Cbr>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Ca href=\"https:\u002F\u002Fdocs.sui.io\u002Fdevelop\u002Ftesting-debugging\u002Ftesting\" rel=\"nofollow\">\u003Cspan>Testing Move Smart Contracts\u003C\u002Fspan>\u003C\u002Fa>\u003Cbr>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Chr>\u003Ch3>\u003Cspan>MoveBit Research &amp; Audit Resources\u003C\u002Fspan>\u003C\u002Fh3>\u003Cul>\u003Cli>\u003Cp>\u003Ca href=\"https:\u002F\u002Fwww.movebit.xyz\u002F?utm_source=chatgpt.com\" rel=\"nofollow\">\u003Cspan>MoveBit Official Website\u003C\u002Fspan>\u003C\u002Fa>\u003Cbr>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fmovebit\u002FSampled-Audit-Reports?utm_source=chatgpt.com\" rel=\"nofollow\">\u003Cspan>\u003Cspan>\u003Cspan>MoveBit Public Audit Reports\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fa>\u003Cbr>\u003C\u002Fp>\u003C\u002Fli>\u003Cli>\u003Cp>\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fmovebit?utm_source=chatgpt.com\" rel=\"nofollow\">\u003Cspan>\u003Cspan>\u003Cspan>MoveBit GitHub Repository\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fspan>\u003C\u002Fa>\u003Cbr>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>\u003Chr>\u003Ch3>\u003Cspan>BitsLab AI\u003C\u002Fspan>\u003C\u002Fh3>\u003Cul>\u003Cli>\u003Cp>\u003Ca href=\"https:\u002F\u002Fwww.movebit.xyz\u002Fblog\u002Fbitslabai-scanner-outperformed-numerous-audit-participants-in-the-competition-securing-second-place?utm_source=chatgpt.com\" rel=\"nofollow\">\u003Cspan>BitsLab AI Scanner: AI-Powered Smart Contract Security Analysis\u003C\u002Fspan>\u003C\u002Fa>\u003C\u002Fp>\u003C\u002Fli>\u003C\u002Ful>","\u002Fmedia\u002Fmovebit\u002F2026\u002F10\u002Fc24af78569a14f376bdc155437a2c0db.png","2026-10-12T07:12:10Z","2026-10-12T15:12:10Z","Sui Shared Object Security: How Access Control Flaws Put DeFi Protocols at Risk cover image",{"slug":39,"category":7,"categoryLabel":6,"subcategoryLabel":17,"authorName":30,"title":40,"excerpt":41,"contentHtml":42,"coverUrl":43,"publishedAt":44,"updatedAt":45,"readTime":46,"cover":43,"hasCover":26,"coverAlt":47},"stable-abi-changing-trust-root-how-the-pyth-core-upgrade-redefines-sui-oracle-security-a30f20","Stable ABI, Changing Trust Root: How the Pyth Core Upgrade Redefines Sui Oracle Security","On August 26, Pyth Core introduced a major infrastructure upgrade. The new architecture preserves compatibility at the Hermes API and on-chain ABI layers, but the underlying verification model changes significantly: the previous path relied on Pythnet and a 13-of-19 Wormhole Guardian signature threshold, while the new design uses five independent routers with a 3-of-5 quorum.","\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">On August 26, Pyth Core introduced a major infrastructure upgrade. The new architecture preserves compatibility at the Hermes API and on-chain ABI layers, but the underlying verification model changes significantly: the previous path relied on Pythnet and a 13-of-19 Wormhole Guardian signature threshold, while the new design uses five independent routers with a 3-of-5 quorum.\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">From an application developer’s perspective, this may look like a relatively smooth infrastructure migration. \u003Cstrong>At MoveBit, we think the more interesting security question is not whether the new Pyth Core remains API-compatible, but whether the protocol consuming it still operates under the same trust assumptions.\u003C\u002Fstrong>\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">From a security perspective, however, it exposes a much deeper issue:\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-indent-start-3 docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14 docx-color-56687a\" style=\"color: rgb(86, 104, 122)\">\u003Cstrong>Stable ABI does not imply a stable trust boundary.\u003C\u002Fstrong>\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">The interface may remain unchanged. Consumer code may not change at all. Yet the answer to a much more important question—\u003Cem>why should this price be trusted?\u003C\u002Fem>—has changed.\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">For Sui protocols that depend on external oracles, the security boundary therefore cannot stop at \u003Cstrong>get_price()\u003C\u002Fstrong>, freshness checks, or confidence intervals. It also has to include oracle versions, verification paths, package identity, and dependency lifecycle.\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">We can describe this class of dependency as \u003Cstrong>Oracle Version Coupling\u003C\u002Fstrong>.\u003C\u002Fspan>\u003C\u002Fp>\u003Ch3 class=\"docx-heading docx-size-22\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-22\">\u003Cstrong>1. Same ABI, Different Trust Root\u003C\u002Fstrong>\u003C\u002Fspan>\u003C\u002Fh3>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">Dependency reviews often treat compatibility and security compatibility as roughly the same thing.\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">If an upgrade preserves function signatures, keeps the ABI compatible, leaves price feed IDs unchanged, and requires no modification to consumer logic, engineers may reasonably conclude that migration risk is limited.\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">But the Pyth Core upgrade shows why that assumption is incomplete.\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">The previous trust path can be simplified as:\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">\u003Cstrong>Pythnet \u003C\u002Fstrong>\u003C\u002Fspan>\u003Cspan class=\"docx-font-arial docx-size-14\">\u003Cstrong>→ \u003C\u002Fstrong>\u003C\u002Fspan>\u003Cspan class=\"docx-size-14\">\u003Cstrong>Wormhole Guardians 13 \u002F 19 signatures \u003C\u002Fstrong>\u003C\u002Fspan>\u003Cspan class=\"docx-font-arial docx-size-14\">\u003Cstrong>→\u003C\u002Fstrong>\u003C\u002Fspan>\u003Cspan class=\"docx-size-14\">\u003Cstrong> Pyth Core \u003C\u002Fstrong>\u003C\u002Fspan>\u003Cspan class=\"docx-font-arial docx-size-14\">\u003Cstrong>→\u003C\u002Fstrong>\u003C\u002Fspan>\u003Cspan class=\"docx-size-14\">\u003Cstrong> Consumer\u003C\u002Fstrong>\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">The new architecture instead looks more like:\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">\u003Cstrong>5 Independent Routers \u003C\u002Fstrong>\u003C\u002Fspan>\u003Cspan class=\"docx-font-arial docx-size-14\">\u003Cstrong>→ \u003C\u002Fstrong>\u003C\u002Fspan>\u003Cspan class=\"docx-size-14\">\u003Cstrong>3 \u002F 5 quorum \u003C\u002Fstrong>\u003C\u002Fspan>\u003Cspan class=\"docx-font-arial docx-size-14\">\u003Cstrong>→ \u003C\u002Fstrong>\u003C\u002Fspan>\u003Cspan class=\"docx-size-14\">\u003Cstrong>Pyth Core \u003C\u002Fstrong>\u003C\u002Fspan>\u003Cspan class=\"docx-font-arial docx-size-14\">\u003Cstrong>→ \u003C\u002Fstrong>\u003C\u002Fspan>\u003Cspan class=\"docx-size-14\">\u003Cstrong>Consumer\u003C\u002Fstrong>\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">From the consumer’s point of view, the same price feed may still arrive through an almost identical interface. Yet the security assumptions behind that price have changed.\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">So an oracle upgrade review should not stop at:\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 6pt\">\u003Cspan class=\"docx-size-14\">\u003Cstrong>ABI Diff \u003C\u002Fstrong>\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 6pt\">\u003Cspan class=\"docx-size-14\">\u003Cstrong>API Diff \u003C\u002Fstrong>\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">\u003Cstrong>Storage Diff\u003C\u002Fstrong>\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">It should also include:\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">\u003Cstrong>Trust-Root Diff\u003C\u002Fstrong>\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">Security reviewers should ask: Who now produces the data? Who can attest to it? What quorum is sufficient? What exactly does the verifier prove? Which failure assumptions changed between versions?\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">API compatibility tells us \u003Cstrong>whether the system can still be called\u003C\u002Fstrong>. Trust-root compatibility tells us \u003Cstrong>whether we can still trust the result for the same reasons\u003C\u002Fstrong>.\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">Those are fundamentally different questions.\u003C\u002Fspan>\u003C\u002Fp>\u003Ch3 class=\"docx-heading docx-size-22\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-22\">\u003Cstrong>2. On Sui, Package Identity Becomes Part of Security State\u003C\u002Fstrong>\u003C\u002Fspan>\u003C\u002Fh3>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">The Pyth migration is particularly interesting on Sui because consumers reference concrete package identities rather than an abstract upgradeable endpoint that can always be switched transparently on their behalf.\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">A simplified dependency chain looks like this:\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">\u003Cstrong>Hermes \u003C\u002Fstrong>\u003C\u002Fspan>\u003Cspan class=\"docx-font-arial docx-size-14\">\u003Cstrong>→ \u003C\u002Fstrong>\u003C\u002Fspan>\u003Cspan class=\"docx-size-14\">\u003Cstrong>Price Payload \u003C\u002Fstrong>\u003C\u002Fspan>\u003Cspan class=\"docx-font-arial docx-size-14\">\u003Cstrong>→ \u003C\u002Fstrong>\u003C\u002Fspan>\u003Cspan class=\"docx-size-14\">\u003Cstrong>Pyth Package \u003C\u002Fstrong>\u003C\u002Fspan>\u003Cspan class=\"docx-font-arial docx-size-14\">\u003Cstrong>→ \u003C\u002Fstrong>\u003C\u002Fspan>\u003Cspan class=\"docx-size-14\">\u003Cstrong>Pyth State \u003C\u002Fstrong>\u003C\u002Fspan>\u003Cspan class=\"docx-font-arial docx-size-14\">\u003Cstrong>→ \u003C\u002Fstrong>\u003C\u002Fspan>\u003Cspan class=\"docx-size-14\">\u003Cstrong>Consumer\u003C\u002Fstrong>\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">Under stable conditions:\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">\u003Cstrong>Old Hermes × Old Verifier ✓ \u003C\u002Fstrong>\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">\u003Cstrong>New Hermes × New Verifier ✓\u003C\u002Fstrong>\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">But during migration, a combination such as:\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">\u003Cstrong>New Hermes × Old Verifier ✕\u003C\u002Fstrong>\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">may fail.\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">Nothing has necessarily been compromised. There is no forged price, no signature bypass, and no corrupted state.\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">Instead, the system enters a more subtle failure mode:\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-indent-start-3 docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14 docx-color-56687a\" style=\"color: rgb(86, 104, 122)\">\u003Cstrong>Version-valid components can still form an invalid system state.\u003C\u002Fstrong>\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">This is why a package ID should not be treated as mere deployment metadata when critical financial operations depend on it.\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">If \u003Cstrong>borrow\u003C\u002Fstrong>, \u003Cstrong>liquidate\u003C\u002Fstrong>, \u003Cstrong>redeem\u003C\u002Fstrong>, or \u003Cstrong>settle\u003C\u002Fstrong> depends on a specific external package, then the identity and lifecycle of that package have effectively become part of the protocol’s runtime security state.\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">That is the practical significance of Oracle Version Coupling.\u003C\u002Fspan>\u003C\u002Fp>\u003Ch3 class=\"docx-heading docx-size-22\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-22\">\u003Cstrong>3. A Dependency Does Not Need Your UpgradeCap to Affect Your Critical Path\u003C\u002Fstrong>\u003C\u002Fspan>\u003C\u002Fh3>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">Traditional access-control reviews focus on capabilities such as:\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">\u003Cstrong>UpgradeCap AdminCap PauseCap TreasuryCap\u003C\u002Fstrong>\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">The goal is to answer a familiar question:\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-indent-start-3 docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14 docx-color-56687a\" style=\"color: rgb(86, 104, 122)\">\u003Cstrong>Who can change the protocol?\u003C\u002Fstrong>\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">But external dependencies create another control plane that may not appear anywhere in the protocol’s own authority graph.\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">Consider a lending protocol that directly binds liquidation logic to a particular Pyth package:\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">\u003Cimg alt=\"IMG_256\" src=\"\u002Fmedia\u002Fmovebit\u002F2026\u002F08\u002F2f7df4a4faf35d1685e10dd6e159eb2f.jpg\" style=\"width: 414.6pt\">\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">Pyth does not hold the lending protocol’s \u003Cstrong>UpgradeCap\u003C\u002Fstrong>. It cannot modify the lending code\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">Yet if the Pyth package lifecycle changes in a way that makes this historical call path unusable, liquidation may still stop working.\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">This leads to a more useful security observation:\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-indent-start-3 docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14 docx-color-56687a\" style=\"color: rgb(86, 104, 122)\">\u003Cstrong>A dependency does not need your UpgradeCap to change the reachability of your critical state transitions.\u003C\u002Fstrong>\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">The right concept here is not “external upgrade authority” in the strict capability sense. It is \u003Cstrong>Dependency-Controlled Availability\u003C\u002Fstrong>.\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">And that dependency can expand the protocol’s real:\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">\u003Cstrong>Effective Upgrade Surface\u003C\u002Fstrong>\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">The protocol’s visible authority graph may look like:\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">\u003Cstrong>Protocol Admin \u003C\u002Fstrong>\u003C\u002Fspan>\u003Cspan class=\"docx-font-arial docx-size-14\">\u003Cstrong>→ \u003C\u002Fstrong>\u003C\u002Fspan>\u003Cspan class=\"docx-size-14\">\u003Cstrong>Protocol Upgrade\u003C\u002Fstrong>\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">But the operational reality may be closer to:\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">\u003Cimg alt=\"IMG_257\" src=\"\u002Fmedia\u002Fmovebit\u002F2026\u002F08\u002Fc9a2684736ccd72b73488d7359ba9d9e.jpg\" style=\"width: 415.2pt\">\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">This is also why hard-coding a specific oracle implementation inside core business logic is fragile.\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">A better pattern is to keep verification at the transaction-construction layer—for example, inside a Programmable Transaction Block—using the currently valid verifier, and let the protocol consume the resulting verified state:\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">\u003Cimg alt=\"IMG_258\" src=\"\u002Fmedia\u002Fmovebit\u002F2026\u002F08\u002F846583b5e5e9efc23e2e81f56860bcd5.jpg\" style=\"width: 414.8pt\">\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">The protocol should ideally depend on the semantic statement:\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">\u003Cstrong>“This price has been validly verified.”\u003C\u002Fstrong>\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">rather than:\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">\u003Cstrong>“This price must be verified by Verifier V1.”\u003C\u002Fstrong>\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">A useful design principle here is:\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-indent-start-3 docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14 docx-color-56687a\" style=\"color: rgb(86, 104, 122)\">\u003Cstrong>Pin semantics, not implementations.\u003C\u002Fstrong>\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">This does not eliminate dependency risk, but it prevents implementation identity from being unnecessarily embedded into core financial logic.\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">This is why MoveBit’s review of oracle-dependent Sui protocols goes beyond price correctness and contract-level integration. The dependency graph itself—package identity, verification assumptions, migration states, and critical-path availability—needs to be treated as part of the protocol’s attack surface.\u003C\u002Fspan>\u003C\u002Fp>\u003Ch3 class=\"docx-heading docx-size-22\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-22\">\u003Cstrong>4. Oracle Upgrades Should Be Audited as Distributed State Transitions\u003C\u002Fstrong>\u003C\u002Fspan>\u003C\u002Fh3>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">Once we accept this model, an oracle upgrade can no longer be reviewed as a simple transition from one package to another:\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">\u003Cstrong>Old Package \u003C\u002Fstrong>\u003C\u002Fspan>\u003Cspan class=\"docx-font-arial docx-size-14\">\u003Cstrong>→ \u003C\u002Fstrong>\u003C\u002Fspan>\u003Cspan class=\"docx-size-14\">\u003Cstrong>New Package\u003C\u002Fstrong>\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">The real dependency graph is broader:\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">\u003Cstrong>Data Infrastructure \u003C\u002Fstrong>\u003C\u002Fspan>\u003Cspan class=\"docx-font-arial docx-size-14\">\u003Cstrong>→ \u003C\u002Fstrong>\u003C\u002Fspan>\u003Cspan class=\"docx-size-14\">\u003Cstrong>Hermes \u003C\u002Fstrong>\u003C\u002Fspan>\u003Cspan class=\"docx-font-arial docx-size-14\">\u003Cstrong>→ \u003C\u002Fstrong>\u003C\u002Fspan>\u003Cspan class=\"docx-size-14\">\u003Cstrong>Signed Payload \u003C\u002Fstrong>\u003C\u002Fspan>\u003Cspan class=\"docx-font-arial docx-size-14\">\u003Cstrong>→ \u003C\u002Fstrong>\u003C\u002Fspan>\u003Cspan class=\"docx-size-14\">\u003Cstrong>Verification Package  \u003C\u002Fstrong>\u003C\u002Fspan>\u003Cspan class=\"docx-font-arial docx-size-14\">\u003Cstrong>→  \u003C\u002Fstrong>\u003C\u002Fspan>\u003Cspan class=\"docx-size-14\">\u003Cstrong>State Object \u003C\u002Fstrong>\u003C\u002Fspan>\u003Cspan class=\"docx-font-arial docx-size-14\">\u003Cstrong>→ \u003C\u002Fstrong>\u003C\u002Fspan>\u003Cspan class=\"docx-size-14\">\u003Cstrong>Consumer Protocol\u003C\u002Fstrong>\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">This exposes another important distinction:\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-indent-start-3 docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14 docx-color-56687a\" style=\"color: rgb(86, 104, 122)\">\u003Cstrong>Blockchain atomicity ends at the transaction boundary; oracle atomicity extends across the dependency graph.\u003C\u002Fstrong>\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">A PTB can execute atomically. But an oracle migration may also involve backend deployment, SDK upgrades, endpoint switching, package migration, state-object updates, and consumer configuration. Those operations do not automatically share the same atomic boundary.\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">That means the most important security target is often not the state before or after the upgrade, but the states in between.\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">A focused review should cover three areas.\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">\u003Cstrong>Trust-Root Diff:\u003C\u002Fstrong> Did the signer set, quorum, verification assumptions, or failure model change?\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">\u003Cstrong>Dependency-Identity Diff:\u003C\u002Fstrong> Does critical business logic directly depend on a package identity that can become obsolete?\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">\u003Cstrong>Migration-State Testing:\u003C\u002Fstrong> What happens under mismatched combinations such as \u003Cstrong>New Data × Old Verifier \u003C\u002Fstrong>or \u003Cstrong>Old Data × New Verifier\u003C\u002Fstrong>? Does the protocol fail closed, fail open, continue consuming stale data, or recover safely?\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">For lending and perpetual protocols, this matters especially because a version mismatch may begin as an availability problem but later become an economic one if stale prices remain usable or liquidations stop executing.\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">The security target should therefore be:\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">\u003Cstrong>Before Upgrade ✓ \u003C\u002Fstrong>\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">\u003Cstrong>During Upgrade ✓ \u003C\u002Fstrong>\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">\u003Cstrong>After Upgrade ✓\u003C\u002Fstrong>\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">—not merely proving that the two stable endpoints work.\u003C\u002Fspan>\u003C\u002Fp>\u003Ch3 class=\"docx-heading docx-size-22\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-22\">\u003Cstrong>5. Practical Recommendations\u003C\u002Fstrong>\u003C\u002Fspan>\u003C\u002Fh3>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">For Sui protocols that depend on upgradeable oracles, a few implementation principles can materially reduce version coupling.\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">First, \u003Cstrong>separate verification from consumption\u003C\u002Fstrong>. Keep the specific verifier implementation outside core financial logic where possible, and let the protocol consume verified price state rather than a hard-coded package call.\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">Second, \u003Cstrong>design a degraded mode for oracle failures\u003C\u002Fstrong>. If verification becomes unavailable, the protocol should generally block risk-increasing actions such as new borrowing or leverage while still allowing risk-reducing actions such as repayment or adding collateral.\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">Third, \u003Cstrong>test migration intermediates explicitly\u003C\u002Fstrong>. Do not validate only the pre-upgrade and post-upgrade configurations. Intentionally test mismatched data\u002Fverifier combinations and make sure the system fails safely and has a clear recovery path.\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">The goal is not to prevent dependencies from ever changing. It is to ensure that dependency evolution does not silently rewrite the protocol’s security boundary.\u003C\u002Fspan>\u003C\u002Fp>\u003Ch3 class=\"docx-heading docx-size-22\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-22\">\u003Cstrong>Conclusion\u003C\u002Fstrong>\u003C\u002Fspan>\u003C\u002Fh3>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">At MoveBit, we believe oracle security should be reviewed as part of the protocol’s full dependency lifecycle—not only at deployment, but through upgrades, migrations, and failure states.\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">The question is no longer just whether a price is correct. It is whether the protocol can continue to verify and consume that price safely as the infrastructure around it evolves.\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-size-14\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-14\">\u003Cstrong>Stable interfaces are useful. Stable security assumptions matter more.\u003C\u002Fstrong>\u003C\u002Fspan>\u003C\u002Fp>","\u002Fmedia\u002Fmovebit\u002F2026\u002F08\u002Fb6aad19bf61579649903f2fc14221cbf.png","2026-08-26T06:45:48Z","2026-08-26T14:45:48Z","7 min read","Stable ABI, Changing Trust Root: How the Pyth Core Upgrade Redefines Sui Oracle Security cover image",{"slug":49,"category":7,"categoryLabel":6,"subcategoryLabel":17,"authorName":30,"title":50,"excerpt":51,"contentHtml":52,"coverUrl":53,"publishedAt":54,"updatedAt":55,"readTime":56,"cover":53,"hasCover":26,"coverAlt":57},"can-aptos-move-really-avoid-reentrancy-what-function-values-changed-13195c","Can Aptos Move Really Avoid Reentrancy? What Function Values Changed","For a long time, many Move developers have operated under a simple assumption: reentrancy is primarily a Solidity problem, and Move largely avoids it by design.","\u003Cp style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">For a long time, many Move developers have operated under a simple assumption: \u003Cstrong>reentrancy is primarily a Solidity problem, and Move largely avoids it by design.\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">That assumption was broadly accurate for earlier versions of Move. Static module dependencies, strict resource semantics, and VM-level protections made the classic Solidity attack pattern difficult to reproduce: an external call re-enters a function before its previous execution has finished, allowing the same state to be manipulated repeatedly.\u003C\u002Fp>\u003Cp style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">With the introduction of \u003Cstrong>Function Values in Aptos Move 2.2\u003C\u002Fstrong>, however, that security model became more nuanced.\u003C\u002Fp>\u003Cp style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">Function Values allow functions to be passed around and invoked dynamically. This makes a call path like the following possible:\u003C\u002Fp>\u003Cp style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">Module A → Module B → Function Value callback → Module A\u003C\u002Fp>\u003Cp style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">Module A can pass a callback to Module B, and B can execute that callback before A&#39;s original execution has completed. In other words, execution can re-enter Module A while the first invocation is still active.\u003C\u002Fp>\u003Cp style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">At first glance, this looks very similar to traditional reentrancy. But there is an important difference.\u003C\u002Fp>\u003Ch3 class=\"docx-heading docx-size-22\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">\u003Cspan class=\"docx-size-22\">Move Still Has Resource Locking\u003C\u002Fspan>\u003C\u002Fh3>\u003Cp style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">When a module is re-entered through a Function Value, the Move VM restricts access to resources defined by that module.\u003C\u002Fp>\u003Cp style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">For example, if Module A is already active and the callback re-enters A, another attempt to access A&#39;s own resource may look like this:\u003C\u002Fp>\u003Cp style=\"line-height: 1.5; margin-bottom: 24.5pt\">borrow_global&lt;Balance&gt;(addr);\u003C\u002Fp>\u003Cp style=\"line-height: 1.5; margin-bottom: 24.5pt\">move_from&lt;Balance&gt;(addr);\u003C\u002Fp>\u003Cp style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">If Balance is defined by the re-entered module, the VM&#39;s resource-locking rules can prevent the second access and abort the transaction.\u003C\u002Fp>\u003Cp style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">This means Function Values do \u003Cstrong>not\u003C\u002Fstrong> simply reintroduce the classic Solidity pattern where an attacker repeatedly withdraws funds before a balance is updated.\u003C\u002Fp>\u003Cp style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">The more interesting security boundary appears one layer deeper.\u003C\u002Fp>\u003Ch3 class=\"docx-heading docx-size-22\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">\u003Cspan class=\"docx-size-22\">Resource Locking Does Not Protect Every Piece of State\u003C\u002Fspan>\u003C\u002Fh3>\u003Cp style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">Resource locking protects resources belonging to the module being re-entered. It does not automatically freeze every external state dependency involved in the transaction.\u003C\u002Fp>\u003Cp style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">Consider a function in Module A with the following execution flow:\u003C\u002Fp>\u003Cp style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">Check external state → Execute user-controlled callback → Continue using the earlier check\u003C\u002Fp>\u003Cp style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">Now assume that the callback can modify a resource managed by another module, or otherwise change external state that Module A relies on.\u003C\u002Fp>\u003Cp style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">A simplified flow might look like this:\u003C\u002Fp>\u003Cp style=\"line-height: 1.5; margin-bottom: 24.5pt\">1. Module A checks that the user&#39;s limit is 100.\u003C\u002Fp>\u003Cp style=\"line-height: 1.5; margin-bottom: 24.5pt\">2. Module A executes an external Function Value.\u003C\u002Fp>\u003Cp style=\"line-height: 1.5; margin-bottom: 24.5pt\">3. The callback modifies state related to that limit.\u003C\u002Fp>\u003Cp style=\"line-height: 1.5; margin-bottom: 24.5pt\">4. Execution returns to Module A.\u003C\u002Fp>\u003Cp style=\"line-height: 1.5; margin-bottom: 24.5pt\">5. Module A continues using the result from step 1.\u003C\u002Fp>\u003Cp style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">The problem is no longer simply “the same balance was withdrawn twice.”\u003C\u002Fp>\u003Cp style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">Instead, the issue becomes a combination of \u003Cstrong>reentrancy, cross-module state manipulation, and TOCTOU — Time of Check to Time of Use\u003C\u002Fstrong>.\u003C\u002Fp>\u003Cp style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">Module A made a security decision based on one version of the state, but by the time that decision is acted upon, the underlying state may have changed.\u003C\u002Fp>\u003Ch3 class=\"docx-heading docx-size-22\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">\u003Cspan class=\"docx-size-22\">Function Values Expand the Trust Boundary\u003C\u002Fspan>\u003C\u002Fh3>\u003Cp style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">This becomes particularly important when a contract accepts arbitrary Function Values, callbacks, or hooks supplied by external callers.\u003C\u002Fp>\u003Cp style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">In those cases, an audit should not stop at asking:\u003C\u002Fp>\u003Cp style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">\u003Cstrong>Can this module&#39;s own resources be accessed twice?\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">It should also ask:\u003C\u002Fp>\u003Cul>\u003Cli>What external state can change while the callback is executing?\u003C\u002Fli>\u003Cli>Do permission, balance, price, or quota checks performed before the callback remain valid afterward?\u003C\u002Fli>\u003Cli>Is the Function Value controlled by the caller?\u003C\u002Fli>\u003Cli>Which modules can that callback invoke?\u003C\u002Fli>\u003Cli>Which resources can those modules modify?\u003C\u002Fli>\u003Cli>Does the original function rely on any state that should be revalidated after control returns?\u003C\u002Fli>\u003C\u002Ful>\u003Cp style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">Where security-sensitive logic depends on mutable external state, critical conditions may need to be checked again at the point of use rather than assuming that a pre-callback validation remains valid.\u003C\u002Fp>\u003Ch3 class=\"docx-heading docx-size-22\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">\u003Cspan class=\"docx-size-22\">The Security Model Has Changed, Not Disappeared\u003C\u002Fspan>\u003C\u002Fh3>\u003Cp style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">The right conclusion is not:\u003C\u002Fp>\u003Cp style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">\u003Cstrong>“Move now has the same reentrancy problem as Solidity.”\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">That would be misleading.\u003C\u002Fp>\u003Cp style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">Move&#39;s VM and resource model still prevent many forms of classic reentrancy. What Function Values change is the boundary of what developers and auditors need to reason about.\u003C\u002Fp>\u003Cp style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">Once \u003Cstrong>Function Values, external resources, and pre-callback state checks\u003C\u002Fstrong> appear in the same execution path, reentrancy-related state changes and TOCTOU conditions become part of the threat model.\u003C\u002Fp>\u003Cp style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">For Move developers, the key question is no longer only whether a module can be re-entered.\u003C\u002Fp>\u003Cp style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">It is also:\u003C\u002Fp>\u003Cp style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">\u003Cstrong>What can change while control is outside the module, and are the assumptions made before that external execution still valid when control returns?\u003C\u002Fstrong>\u003C\u002Fp>\u003Cp style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">That is the security boundary Function Values have introduced into modern Aptos Move.\u003C\u002Fp>\u003Cp style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">At \u003Cstrong>MoveBit\u003C\u002Fstrong>, we review not only isolated functions, but also the state transitions and trust boundaries created by callbacks, Function Values, and cross-module interactions.\u003C\u002Fp>\u003Cp style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">If you&#39;re building on Aptos or other Move-based ecosystems, these are exactly the kinds of edge cases that deserve attention before deployment.\u003C\u002Fp>\u003Cp style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24.5pt\">— \u003Cstrong>MoveBit Research\u003C\u002Fstrong>\u003C\u002Fp>","\u002Fmedia\u002Fmovebit\u002F2026\u002F08\u002F2e24434a92f775515edf49221e289d0c.jpg","2026-08-18T03:18:54Z","2026-08-18T11:24:25Z","4 min read","Can Aptos Move Really Avoid Reentrancy? What Function Values Changed cover image",{"slug":59,"category":7,"categoryLabel":6,"subcategoryLabel":60,"authorName":30,"title":61,"excerpt":62,"contentHtml":63,"coverUrl":64,"publishedAt":65,"updatedAt":66,"readTime":67,"cover":64,"hasCover":26,"coverAlt":68},"when-account-history-was-misclassified-as-deposit-proof-a-technical-analysis-of-the-xrpl-coreum-bridge-vulnerability-f867e8","Incident Analysis","When Account History Was Misclassified as Deposit Proof: A Technical Analysis of the XRPL–Coreum Bridge Vulnerability","The issue in the XRPL–Coreum bridge incident appears straightforward: when identifying inbound XRPL transfers, the relayer failed to verify whether the Payment Destination was the bridge address.","\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">The issue in the XRPL–Coreum bridge incident appears straightforward: when identifying inbound XRPL transfers, the relayer failed to verify whether the Payment Destination was the bridge address.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">However, treating the incident as nothing more than a missing if statement would miss the more important issue. The relayer used an incomplete set of conditions to determine whether an XRPL transaction represented a valid bridge deposit. As a result, a transaction associated with the bridge account could be incorrectly classified as an inbound deposit and then converted into evidence accepted on the Coreum side.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">The vulnerability therefore involved more than a single field check. It affected transaction discovery, inbound transfer classification, memo parsing, evidence generation, and the multi-relayer verification process.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">From MoveBit’s security research perspective, this is also a useful case for examining a broader class of cross-chain risks. A contract on the destination chain may be secure, while the off-chain component responsible for interpreting source-chain transactions introduces incorrect state. For Move-based bridges, this boundary deserves the same level of review as the on-chain contract itself.\u003C\u002Fp>\u003Cp class=\"docx-align-justify docx-size-18\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-18\">1. account_tx Can Discover Transactions, but It Cannot Prove a Deposit\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">The Coreum relayer monitors the bridge account using XRPL’s account_tx RPC method. This is a reasonable approach because account_tx returns validated transactions associated with a specified account and can therefore be used to identify candidate transactions for further processing.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">The problem is that a transaction being associated with an account does not mean that the transaction transferred assets to that account.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">The results returned by account_tx should therefore be treated only as candidate transactions. Before classifying any of them as an XRPL-to-Coreum deposit, the relayer still needs to verify the Payment direction, destination, asset, amount, memo, and other relevant fields.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">The processing logic can be simplified as follows:\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-bottom: 24pt\">\u003Cimg alt=\"1111111\" src=\"\u002Fmedia\u002Fmovebit\u002F2026\u002F08\u002Fa255d020e432cb797f063461a93e72a7.jpg\" style=\"width: 264.2pt\">\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-bottom: 24pt\">The problem is that the code effectively sends any transaction not initiated by the bridge into the incoming-transaction processing path.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">A transaction not being sent by the bridge does not mean that it was sent to the bridge. A correct inbound Payment check must at least confirm:\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">require(payment.Destination == bridgeAddress)\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-bottom: 24pt\">Without this check, a transaction that involves the bridge account but does not actually transfer funds to it may still be processed as a deposit.\u003C\u002Fp>\u003Cp class=\"docx-align-justify docx-size-18\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-18\">2. The Relayer Validated the Transaction State but Not the Full Deposit Conditions\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">The incoming-transaction path did perform several validations. The public implementation can be simplified to something like:\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cimg alt=\"222222\" src=\"\u002Fmedia\u002Fmovebit\u002F2026\u002F08\u002F74001cf6561c302ac19ff3aef0b1000f.jpg\" style=\"width: 298.3pt\">\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">These checks confirm that the XRPL transaction was validated, that the Payment succeeded, that the transaction type was correct, that a Coreum recipient could be extracted from the memo, and that the delivered amount could be obtained from the transaction metadata.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">However, these conditions are still not enough to prove that the bridge received the funds.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">DeliveredAmount is particularly important here. It represents the amount actually delivered by a Payment to its recipient, but it does not independently prove that the recipient was the bridge. Even if tx.success == true and DeliveredAmount is present, the transaction cannot automatically be treated as a bridge deposit.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">The validation logic must also enforce:\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cimg alt=\"3333333\" src=\"\u002Fmedia\u002Fmovebit\u002F2026\u002F08\u002Fd9fa1cace233519377d2ddbc2a13b2c6.jpg\" style=\"width: 271.2pt\">\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">The underlying transaction may therefore be completely valid on XRPL while still failing to satisfy the bridge’s own deposit requirements.\u003C\u002Fp>\u003Cp class=\"docx-align-justify docx-size-18\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-18\">3. Memo Data Should Be Used for Routing, Not as Proof of Deposit\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">The XRPL–Coreum bridge uses memos to carry cross-chain routing information, such as the destination Coreum address. The relayer parses this memo to determine where the bridged assets should eventually be credited on Coreum.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">This design is common, but memo data is controlled by the transaction sender. It can provide routing information, but it should not be used as evidence that a valid bridge deposit occurred.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">An attacker can construct a valid XRPL Payment containing a correctly formatted bridge memo. A valid memo only proves that the transaction contains data matching the bridge’s expected format. It does not prove that the Payment Destination is the bridge.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">A safer processing order is:\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cimg alt=\"444444\" src=\"\u002Fmedia\u002Fmovebit\u002F2026\u002F08\u002F0fe82016b32180024c3cc691a55673a0.jpg\" style=\"width: 166.2pt\">\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">The system should first confirm that the transaction actually transferred assets to the bridge, then verify the asset and amount, and only after that use the memo to determine the cross-chain recipient.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">If the destination has not yet been verified, attacker-controlled memo data should not be allowed to influence evidence generation.\u003C\u002Fp>\u003Cp class=\"docx-align-justify docx-size-18\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-18\">4. Missing Destination Data in the Evidence Limited Coreum-Side Verification\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">Another important issue is the loss of transaction context when XRPL data is converted into evidence for Coreum.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">The public XRPLToCoreumTransferEvidence structure is roughly:\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cimg alt=\"5555555\" src=\"\u002Fmedia\u002Fmovebit\u002F2026\u002F08\u002Ff71eca57bad8594ccb831c9a5eecc809.jpg\" style=\"width: 252.9pt\">\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">The XRPL Payment Destination is not included.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">This means that the relayer has access to the full XRPL transaction during processing, but after the evidence object is created, the Coreum side receives only a subset of those fields.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">The original transaction contains information such as the sender, destination, asset, amount, transaction result, and memo. The evidence retains only part of that context.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">As a result, if the relayer fails to validate the destination before creating the evidence, the Coreum contract may not have enough information to independently confirm that the Payment was actually sent to the bridge.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">This design pattern requires careful handling. Any field that directly determines whether cross-chain assets can be credited or released should be fully validated before evidence is created. Where appropriate, fields such as Destination can also be included in the evidence so that the on-chain logic can perform an additional check.\u003C\u002Fp>\u003Cp class=\"docx-align-justify docx-size-18\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-18\">5. Multiple Relayers Do Not Protect Against Shared Validation Bugs\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">The Coreum bridge uses an evidence-threshold mechanism. Multiple trusted relayers must submit matching evidence before the bridge proceeds with the cross-chain workflow.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">This mechanism can reduce the risk of a single relayer acting maliciously, being compromised, or malfunctioning. However, it does not automatically protect against a validation bug shared by every relayer.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">If multiple relayers run the same software version and that implementation is missing the Destination == bridgeAddress check, each relayer may classify the same invalid transaction in the same way and submit matching evidence.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">The process can look like this:\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cimg alt=\"666666\" src=\"\u002Fmedia\u002Fmovebit\u002F2026\u002F08\u002F1c1501d8a74a280b3566691893b1627e.jpg\" style=\"width: 204.1pt\">\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">An N-of-M relayer model shows that multiple relayers reached the same conclusion about a transaction. It does not prove that the classification rule used by those relayers is correct.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">Relayer count and relayer validation logic are therefore separate security concerns. Increasing the number of relayers reduces certain single-point-of-failure risks, but it does not prevent a shared software defect from reaching the evidence threshold.\u003C\u002Fp>\u003Cp class=\"docx-align-justify docx-size-18\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-18\">6. Multisig Protects Signing Authority, but It Cannot Correct Invalid Bridge State\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">Assets on the XRPL side of the bridge are protected by a multisignature account. Multisig reduces the risk that a single private key or signer can directly control bridge funds.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">However, the vulnerability occurred earlier in the workflow, during state validation.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">If invalid deposit evidence has already been accepted on Coreum and the system generates a withdrawal request based on that state, the withdrawal may appear completely valid to the signers.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">In that situation, the final XRP transaction can be generated through the normal workflow and signed by the required number of authorized signers. The multisig mechanism has not been bypassed, and the signature process itself is functioning correctly.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">The problem is that the withdrawal was created from incorrect cross-chain state.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">Multisig can prevent unauthorized transfers, but it cannot determine whether the deposit evidence that produced a withdrawal request was valid. Custody security and cross-chain state verification therefore need separate controls. Multisig cannot replace upstream transaction validation.\u003C\u002Fp>\u003Cp class=\"docx-align-justify docx-size-18\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-18\">7. Incoming Payment Verification Should Bind All Deposit-Critical Fields\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">A safer implementation should fully validate whether an Incoming Payment satisfies the definition of a bridge deposit before generating evidence.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">For example:\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cimg alt=\"777777\" src=\"\u002Fmedia\u002Fmovebit\u002F2026\u002F08\u002F0e207cd3c56c625332bff6f14cd96b27.jpg\" style=\"width: 295pt\">\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">The destination check is only one part of the solution. Sender, destination, asset, amount, recipient, and transaction hash should all be included in the validation logic.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">Only after all of these conditions are satisfied should the transaction be classified as a valid XRPL-to-Coreum deposit and used to generate cross-chain evidence.\u003C\u002Fp>\u003Cp class=\"docx-align-justify docx-size-18\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-18\">8. Tests Should Cover Transactions That Are Valid on XRPL but Invalid for the Bridge\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">Bridge relayer tests should not focus only on normal deposits and obviously malformed transactions. They should also cover transactions that are fully valid under XRPL rules but do not satisfy the bridge’s business logic.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">Examples include:\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cimg alt=\"8888888\" src=\"\u002Fmedia\u002Fmovebit\u002F2026\u002F08\u002F7364f4b31a61bba11702114a4fcbdec3.jpg\" style=\"width: 300.4pt\">\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">All of these transactions may pass XRPL consensus and execute successfully. Their validity at the protocol level therefore cannot be used as proof that they represent valid bridge deposits.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">The relayer must apply bridge-specific semantic validation on top of the source chain’s transaction rules.\u003C\u002Fp>\u003Cp class=\"docx-align-justify docx-size-18\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-18\">9. Runtime Monitoring Can Provide a Second Layer of Protection\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">In addition to fixing the transaction-validation logic, a bridge should monitor reserves and cross-chain accounting for abnormal behavior.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">The Coreum bridge already includes a kill switch. This mechanism can be combined with asset-flow and accounting checks so that unusual conditions trigger an alert or halt.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">For example:\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cimg alt=\"999999\" src=\"\u002Fmedia\u002Fmovebit\u002F2026\u002F08\u002Ff76fd144e8f3bac3eb47ce7b74c1df33.jpg\" style=\"width: 253.2pt\">\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">These controls do not replace relayer validation, but they can provide additional protection if a bug in the verification logic allows invalid state to enter the system.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">This is especially important for bridges because they combine several independent components, including source-chain parsing, off-chain relayers, threshold verification, smart contracts, key management, and asset accounting. A failure in one component should not automatically result in unrestricted asset outflow.\u003C\u002Fp>\u003Cp class=\"docx-align-justify docx-size-18\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-18\">Implications for Move Developers\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">The same issue is particularly relevant to cross-chain systems built in the Move ecosystem. In MoveBit’s security work across Move-based networks, bridge security cannot be evaluated only from the Move contract layer. The relayer and source-chain verification logic are also part of the system that determines whether assets can be minted, credited, or released.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">Move’s type system, resource model, ownership rules, and bytecode verification can prevent many classes of on-chain asset-handling errors. However, these mechanisms can only ensure that Move code executes safely according to the state and inputs it receives. They cannot determine whether information supplied by an off-chain system or another blockchain is correct.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">If an off-chain relayer submits invalid deposit evidence to a Move contract and the contract has no independent way to verify the corresponding source-chain transaction, the contract may still mint assets, update balances, or allow withdrawals based on incorrect evidence, even if the Move code itself has no type-safety or resource-management flaws.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">For Move bridges and other cross-chain infrastructure, this is why MoveBit’s security reviews look beyond the Move contracts themselves. Relayer behavior, source-chain transaction parsing, evidence construction, replay protection, and the handling of security-critical fields all need to be reviewed when they can directly affect on-chain asset state.\u003C\u002Fp>\u003Cp class=\"docx-align-justify docx-size-18\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">\u003Cspan class=\"docx-size-18\">Security Takeaway\u003C\u002Fspan>\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">The immediate issue in the XRPL–Coreum bridge incident was the absence of a Destination == bridgeAddress check in the Incoming Payment flow. At the system level, however, the more important problem was that the relayer used incomplete conditions to determine whether an XRPL transaction represented a valid bridge deposit.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">A source-chain transaction executing successfully only proves that it satisfies the source chain’s protocol rules. It does not prove that it satisfies the bridge’s deposit requirements. The relayer must independently validate the destination, asset, amount, transaction result, memo, transaction hash, and any other fields that directly affect bridge accounting before generating evidence for the destination chain.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">Multi-relayer thresholds, multisig custody, and Move’s on-chain safety mechanisms address different categories of risk. None of them can replace complete source-chain event validation.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">For cross-chain systems, one of the most important security questions is simple: \u003Cstrong>what exact conditions must be satisfied before a source-chain transaction is classified as a valid bridge deposit?\u003C\u002Fstrong> Those conditions should be explicit, complete, and enforced before the evidence is submitted to the destination chain.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">For MoveBit, this is also an important part of how we approach cross-chain security. Reviewing a Move contract alone is not enough when off-chain relayers, source-chain parsers, and evidence-generation logic can directly change the state that the contract receives. A complete bridge security review needs to cover both the on-chain execution logic and the components responsible for producing cross-chain evidence.\u003C\u002Fp>\u003Cp class=\"docx-align-justify\" style=\"line-height: 1.5; margin-top: 0pt; margin-bottom: 24pt\">MoveBit continues to research security issues across Move-based ecosystems, with a focus on smart contract security, cross-chain infrastructure, and the assumptions that affect asset safety beyond the contract itself.\u003C\u002Fp>","\u002Fmedia\u002Fmovebit\u002F2026\u002F08\u002F17300163bfb6286567e0bfa39953ad61.png","2026-08-13T05:40:59Z","2026-08-13T13:40:59Z","10 min read","When Account History Was Misclassified as Deposit Proof: A Technical Analysis of the XRPL–Coreum Bridge Vulnerability cover image",{"slug":70,"category":7,"categoryLabel":6,"subcategoryLabel":17,"authorName":18,"title":71,"excerpt":72,"contentHtml":73,"coverUrl":74,"seoTitle":71,"seoDescription":75,"seoImageUrl":74,"publishedAt":76,"updatedAt":77,"readTime":46,"cover":74,"hasCover":26,"coverAlt":78},"bitslab-deep-dive-nanobot-user-security-practice-guide","BitsLab Deep Dive | Nanobot User Security Practice Guide","When an AI Agent possesses system-level capabilities such as shell execution, file read\u002Fwrite, network requests, and scheduled tasks, it is no longer just a \"chatbot\"—it is an operator with real permissions. This means a single command triggered by prompt injection could delete critical data; a supply chain-poisoned Skill could quietly leak credentials; and an unverified business operation could cause irreversible loss.","\u003Col>\n\u003Cli>Introduction\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>When an AI Agent possesses system-level capabilities such as shell execution, file read\u002Fwrite, network requests, and scheduled tasks, it is no longer just a “chatbot”—it is an operator with real permissions. This means: a single command triggered by prompt injection could delete critical data; a supply chain-poisoned Skill could quietly leak credentials; and an unverified business operation could cause irreversible loss.\u003Cbr>Traditional security solutions usually lean toward two extremes: either relying entirely on the AI’s own “judgment” for self-restraint (which is easily bypassed by meticulously crafted prompts) or piling up rigid rules that lock the Agent down (stripping away the Agent’s core value).\u003C\u002Fp>\n\u003Cp>This guide chooses a third path: dividing security responsibilities based on “who performs the check,” ensuring three distinct roles fulfil their respective duties:\u003C\u002Fp>\n\u003Cp>General Users: Serving as the final line of defence, responsible for key decisions and periodic reviews. We provide best practices to reduce cognitive load.\u003Cbr>The Agent Itself: Consciously adhering to behavioural norms and audit processes during runtime. We provide Skills to inject security knowledge directly into the Agent’s context.\u003Cbr>Deterministic Scripts: Mechanically and faithfully executing checks, immune to prompt injection. We provide Scripts to cover common, known danger patterns.\u003C\u002Fp>\n\u003Cp>No single checker is omnipotent. Scripts cannot understand semantics, Agents can be deceived, and humans experience fatigue. However, by combining all three, we can guarantee the convenience of daily use while simultaneously defending against high-risk operations.\u003C\u002Fp>\n\u003Col start=\"2\">\n\u003Cli>General Users (Precautions)\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>Users are the ultimate line of defence and the holders of the highest authority in the security system. The following are security matters that users must personally attend to and execute.\u003C\u002Fp>\n\u003Cp>a) API Key Management: \u003C\u002Fp>\n\u003Cp>Set proper permissions for configuration files to prevent unauthorised access:\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"\u002Fmedia\u002Fmovebit\u002F2026\u002F03\u002F420ceff72b521dc5bc9aa803a70fd621.png\" alt=\"Figure1\" title=\"Figure1\">\u003C\u002Fp>\n\u003Cp>Never commit API keys to code repositories!\u003C\u002Fp>\n\u003Cp>b) Channel Access Control (Critical!)\u003Cbr>You must set a whitelist (allowFrom) for every communication channel; otherwise, anyone will be able to chat with your Agent:\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"\u002Fmedia\u002Fmovebit\u002F2026\u002F03\u002F5f3b8d41207ad04c113c498586d1e381.png\" alt=\"Figure2\" title=\"Figure2\">\u003C\u002Fp>\n\u003Cp>⚠️ In the new version, an empty allowFrom means all access is denied. If you want to open it, you must explicitly write [“*”], but this is not recommended.\u003C\u002Fp>\n\u003Cp>c) Do Not Run as Root\u003Cbr>It is recommended to create a dedicated user to run the Agent to avoid excessive permissions:\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"\u002Fmedia\u002Fmovebit\u002F2026\u002F03\u002F4f251bae7690fd1a0b6b0c7d80bfdef1.png\" alt=\"Figure3\" title=\"Figure3\">\u003C\u002Fp>\n\u003Cp>d) Avoid Using Email Channels Where Possible \u003C\u002Fp>\n\u003Cp>Email protocols are complex and carry relatively high risks. Our BitsLab team has discovered and confirmed a [Critical] level vulnerability related to email. Below is the project team’s response; we still have several issues awaiting their confirmation, so please exercise caution when using email-related functional modules.\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"\u002Fmedia\u002Fmovebit\u002F2026\u002F03\u002F746713b798b1fdd1140b4e3f849f3b7b.png\" alt=\"Figure4\" title=\"Figure4\">\u003C\u002Fp>\n\u003Cp>e) Recommended Deployment in Docker\u003Cbr>It is recommended to deploy Nanobot in a Docker container to isolate it from your daily operating environment, preventing security risks caused by mixed permissions or environments.\u003C\u002Fp>\n\u003Col start=\"3\">\n\u003Cli>Tool Installation Steps\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>The following tools are part of the proprietary toolkit developed by BitsLab. For more details, visit the official repository: \u003Ca target=\"_blank\" rel=\"noopener\" href=\"https:\u002F\u002Fgithub.com\u002FBitsLabSec\u002Fnanobot-security-guide\">https:\u002F\u002Fgithub.com\u002FBitsLabSec\u002Fnanobot-security-guide\u003C\u002Fa>\u003C\u002Fp>\n\u003Cp>① Download the nanobot-security-guide project to your nanobot skills directory, or send a command to the Agent to run the official installation script:\u003Cbr>curl -sSL \u003Ca target=\"_blank\" rel=\"noopener\" href=\"https:\u002F\u002Fraw.githubusercontent.com\u002FBitsLabSec\u002Fnanobot-security-guide\u002Fmain\u002Finstall.sh\">https:\u002F\u002Fraw.githubusercontent.com\u002FBitsLabSec\u002Fnanobot-security-guide\u002Fmain\u002Finstall.sh\u003C\u002Fa> | bash\u003Cbr>↓\u003Cbr>② Once installation is complete, read the security practice guides within the project (such as README.md and SKILL.md) to understand core security configurations and operational recommendations.\u003Cbr>↓\u003Cbr>③ Send a command to your Agent: “Please read this security guide carefully and evaluate whether it is reliable.”\u003Cbr>↓\u003Cbr>④ Following the document prompts, manually configure allowlist.txt and runtime-baseline.txt in the policy\u002F directory to tighten permissions and establish security baselines.\u003Cbr>↓\u003Cbr>⑤ Use the scripts in the scripts\u002F directory to perform security inspections and testing to ensure environmental safety.\u003C\u002Fp>\n\u003Col start=\"4\">\n\u003Cli>Tool Principles\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>SKILL.md \u003C\u002Fp>\n\u003Cp>Intent auditing based on “Cognitive Awakening” breaks through the blind spots where traditional AI passively receives instructions. It features a built-in, mandatory “Self-Wakeup” Chain of Thought (CoT) mechanism that requires the AI to awaken an independent security-auditor persona in the background before processing any user request. By performing contextual analysis and independent judgment of user intent, it actively identifies and intercepts potential high-risk threats, upgrading the system from “mechanical execution” to an “Intelligent Firewall.” When malicious commands (such as reverse shells, sensitive file theft, or large-scale deletions) are detected, the tool executes a standardised hard-interception protocol (outputting a warning: [Bitslab nanobot-sec skills detected sensitive operation…, Intercepted]).\u003C\u002Fp>\n\u003Cp>Malicious Command Execution Interception (Shell &amp; Cron Protection) \u003C\u002Fp>\n\u003Cp>Acts as a “Zero Trust” gateway when the Agent interacts with OS-level commands. This line of defence directly blocks various destructive operations and dangerous payloads (such as rm -rf malicious deletions, permission tampering, reverse shells, etc.). Simultaneously, the tool provides deep runtime inspection capabilities, actively scanning and cleaning system processes and cron jobs for persistent backdoors and malicious execution signatures, ensuring the absolute safety of the local environment.\u003C\u002Fp>\n\u003Cp>Sensitive Data Theft Prevention (File Access Validation) \u003C\u002Fp>\n\u003Cp>Implements strict physical read\u002Fwrite isolation for core assets. The system presets rigorous file validation rules, strictly forbidding the AI from unauthorised reading and exfiltration of sensitive files containing API keys and core configurations, such as config.json or .env. Furthermore, the security engine performs real-time auditing of file-reading logs (e.g., the invocation sequence of the read_file tool) to completely sever the possibility of credential leakage or data exfiltration at the source.\u003C\u002Fp>\n\u003Cp>MCP Skill Security Auditing \u003C\u002Fp>\n\u003Cp>For the MCP (Model Context Protocol) class, the tool automatically audits contextual interactions and data-processing logic. It detects risks such as sensitive information leakage, unauthorised access, and dangerous command injections, and cross-references them against security baselines and whitelists.\u003C\u002Fp>\n\u003Cp>New Skill Downloads and Automated Security Scanning \u003C\u002Fp>\n\u003Cp>When downloading new skills, the tool uses auditing scripts to perform automated static analysis of the code, compare it against security baselines and whitelists, and detect sensitive information or dangerous commands. This ensures that skills are safe and compliant before they are loaded.\u003C\u002Fp>\n\u003Cp>Anti-Tamper Hash Baseline Verification \u003C\u002Fp>\n\u003Cp>To ensure absolute Zero Trust of underlying system assets, the protection shield continuously establishes and maintains SHA256-encrypted signature baselines for critical configuration files and memory nodes. The nightly inspection engine automatically verifies chronological changes in file hashes, capturing any unauthorised tampering or malicious overwrites within milliseconds. This completely eliminates the risk of local backdoor implantation or “poisoning” at the physical storage layer.\u003C\u002Fp>\n\u003Cp>Automated Disaster Recovery Backup and Snapshot Rotation. \u003C\u002Fp>\n\u003Cp>Given that local Agents possess high-level read\u002Fwrite permissions for the file system, the system includes a top-tier automated disaster recovery mechanism. The protection engine automatically triggers a full sandbox-level archive of active workspaces every night, maintaining a security snapshot mechanism with a 7-day retention policy (auto-rotation). Even in extreme cases of accidental damage or erroneous deletion, the development environment can be rolled back losslessly with one click, maximising the continuity and resilience of local digital assets.\u003C\u002Fp>\n\u003Col start=\"5\">\n\u003Cli>Disclaimer\u003Cbr>This guide is intended solely as a reference for security practices and does not constitute any form of security guarantee.\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>No Absolute Security: All measures described in this guide (including deterministic scripts, Agent Skills, and user precautions) are “best-effort” protections and cannot cover all attack vectors. AI Agent security is a rapidly evolving field, and new attack methods may emerge at any time.\u003C\u002Fp>\n\u003Cp>User Responsibility: Users deploying and using Nanobot should independently assess the security risks of their operating environment and adjust the recommendations in this guide according to their specific scenarios. Any losses resulting from incorrect configuration, failure to update promptly, or ignoring security warnings are the sole responsibility of the user.\u003C\u002Fp>\n\u003Cp>Not a Substitute for Professional Security Audits: This guide is not a replacement for professional security audits, penetration testing, or compliance assessments. For scenarios involving sensitive data, financial assets, or critical infrastructure, it is strongly recommended to hire a professional security team for an independent evaluation.\u003C\u002Fp>\n\u003Cp>Third-Party Dependencies: The security of third-party libraries, API services, and platforms that Nanobot relies on (such as Telegram, WhatsApp, and LLM providers) is beyond the scope of this guide. Users should monitor security advisories for relevant dependencies and update them promptly.\u003C\u002Fp>\n\u003Cp>Scope of Non-Liability: The maintainers and contributors of the Nanobot project shall not be held liable for any direct, indirect, incidental, or consequential damages arising from the use of this guide or the Nanobot software.\u003C\u002Fp>\n\u003Cp>Use of this software indicates that you understand and accept the aforementioned risks.\u003C\u002Fp>","\u002Fmedia\u002Fmovebit\u002F2026\u002F03\u002F3c4245d7eca88c6e2e913dac30c8d36e.jpg","When an AI Agent possesses system-level capabilities such as shell execution, file read\u002Fwrite, network requests, and scheduled tasks, it is no longer just a \"chatbot\"—it is an operator with real permissions. This means a single command triggered by prompt injection could delete critical data; a supply chain-poisoned Sk","2026-03-11T03:15:00Z","2026-08-11T17:56:38Z","BitsLab Deep Dive | Nanobot User Security Practice Guide cover image",{"slug":80,"category":7,"categoryLabel":6,"subcategoryLabel":17,"authorName":18,"title":81,"excerpt":82,"contentHtml":83,"coverUrl":84,"seoTitle":81,"seoDescription":85,"seoImageUrl":84,"publishedAt":86,"updatedAt":77,"readTime":87,"cover":84,"hasCover":26,"coverAlt":88},"bitslab-research-kasplex-l2-a-light-weight-based-rollup-solution-on-kaspa","BitsLab Research | Kasplex L2 A Light-Weight Based Rollup Solution on Kaspa","As blockchain technology evolves, scalability and programmability remain critical challenges, particularly for blockchains using the UTXO model. Kaspa, a Layer 1 blockchain leveraging a BlockDAG structure, achieves high throughput but lacks native smart contract functionality, a limitation shared by other UTXO-based systems like Bitcoin. To address this, the Kaspa ecosystem has developed Kasplex L2, a Layer 2 solution designed to enable Ethereum Virtual Machine (EVM) compatible smart contracts through a based rollup architecture.","\u003Ch2 id=\"Introduction\">Introduction\u003C\u002Fh2>\n\u003Cp>As blockchain technology evolves, scalability and programmability remain critical challenges, particularly for blockchains using the UTXO model. Kaspa, a Layer 1 blockchain leveraging a BlockDAG structure, achieves high throughput but lacks native smart contract functionality, a limitation shared by other UTXO-based systems like Bitcoin. To address this, the Kaspa ecosystem has developed Kasplex L2, a Layer 2 solution designed to enable Ethereum Virtual Machine (EVM) compatible smart contracts through a based rollup architecture.\u003C\u002Fp>\n\u003Cp>In this article, we provide a technical analysis of Kasplex L2 from the perspective of a security and research firm. Our goal is to evaluate its design, implementation, and implications for UTXO-based blockchains, without advocating for Kaspa or its ecosystem. We’ll explore how Kasplex L2 works, compare it to Bitcoin’s Inscriptions (e.g., BRC-20), and assess its strengths and limitations. This analysis aims to contribute to the broader discourse on scaling solutions for blockchains with constrained programmability.\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"\u002Fmedia\u002Fmovebit\u002F2025\u002F05\u002F53cb218effcd84232c837c60e5bbc2af.png\" alt=\"Banner\" title=\"Banner\">\u003C\u002Fp>\n\u003Ch2 id=\"Understanding-Kaspa-Layer-1-A-High-Throughput-UTXO-Blockchain\">Understanding Kaspa Layer 1: A High-Throughput UTXO Blockchain\u003C\u002Fh2>\n\u003Cp>Kaspa is a Layer 1 blockchain that uses a BlockDAG structure, allowing multiple blocks to be produced in parallel. This design, powered by the GHOSTDAG protocol, enables Kaspa to achieve a throughput of 10 BPS performance. Unlike account-based blockchains such as Ethereum, Kaspa employs a UTXO model, where transactions consume unspent outputs and create new ones, ensuring efficient validation.\u003C\u002Fp>\n\u003Cp>While this architecture excels for payment use cases, it poses challenges for programmability. The UTXO model is stateless by nature, lacking the ability to maintain persistent state or execute complex computations—key requirements for smart contracts. As a result, Kaspa’s functionality is limited to simple transfers, prompting the development of Layer 2 solutions to expand its capabilities.\u003C\u002Fp>\n\u003Ch2 id=\"Kasplex-L2-A-Based-Rollup-for-Smart-Contract-Execution\">Kasplex L2: A Based Rollup for Smart Contract Execution\u003C\u002Fh2>\n\u003Cp>The Kaspa ecosystem has explored three L2 approaches: Sparkle, Igra L2, and Kasplex L2. Sparkle remains largely theoretical, and Igra L2 trails in development. Our analysis focuses on Kasplex L2, as it represents the most mature implementation to date.\u003C\u002Fp>\n\u003Cp>Kasplex L2 is a based rollup, a type of Layer 2 scaling solution that relies on the L1 for transaction sequencing and data availability, while offloading computation to the L2. In this design, Kaspa’s L1 determines the canonical order of transactions and ensures their data is publicly accessible, while Kasplex L2 executes EVM bytecode to enable smart contract functionality.\u003C\u002Fp>\n\u003Ch2 id=\"Technical-Design-and-Workflow\">Technical Design and Workflow\u003C\u002Fh2>\n\u003Cp>The core mechanism of Kasplex L2 involves embedding EVM bytecode in the payload of Kaspa L1 transactions. The process can be broken down as follows:\u003C\u002Fp>\n\u003Cp>Transaction Submission: A user submits a transaction to Kaspa L1, including a payload that contains EVM bytecode. For example, the payload might encode a call to a smart contract function like HelloWorld().\u003C\u002Fp>\n\u003Cp>Sequencing by L1: Kaspa’s BlockDAG orders the transaction within its DAG structure, providing a deterministic sequence of all transactions.\u003C\u002Fp>\n\u003Cp>L2 Execution: Kasplex L2 operates as an indexer, scanning the L1 for transactions with payloads. It extracts the EVM bytecode, executes it in the specified order, and updates its state. Invalid or conflicting transactions (e.g., those attempting to double-spend) are discarded.\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"\u002Fmedia\u002Fmovebit\u002F2025\u002F05\u002Fb17ab6f1cc2e19dd7f31fe15c54a8fce.png\" alt=\"Figure1\" title=\"Figure1\">\u003C\u002Fp>\n\u003Ch2 id=\"Transaction-Submission-Mechanisms\">Transaction Submission Mechanisms\u003C\u002Fh2>\n\u003Cp>Kasplex L2 supports two methods for submitting transactions, each with distinct implications:\u003C\u002Fp>\n\u003Cp>Canonical Submission: Transactions are submitted directly to Kaspa L1 using a Kaspa-compatible wallet. This approach ensures that no intermediaries are involved, aligning with the decentralization principles of blockchain systems.\u003Cbr>Proxied Submission: Transactions are submitted via a relayer, enabling compatibility with EVM-based tools like MetaMask. The relayer forwards the transaction to Kaspa L1, ensuring it is recorded before the L2 processes it. This method prioritizes user convenience but introduces a dependency on the relayer.\u003C\u002Fp>\n\u003Cp>The proxied submission mechanism enforces atomicity by requiring all L2 transactions to be anchored on the L1. If a transaction originates on the L2 without an L1 record, the relayer submits it to the L1 for confirmation. This design prevents “native” L2 transactions, which could bypass L1 consensus and introduce security risks. Figure 2 illustrates the two submission paths.\u003C\u002Fp>\n\u003Cp>Canonical Path: Wallet → Kaspa L1 → Kasplex L2 .\u003Cbr>Proxied Path: MetaMask → Relayer → Kaspa L1 → Kasplex L2.\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"\u002Fmedia\u002Fmovebit\u002F2025\u002F05\u002Fdd924831a8b9a2cba4f66b2453121c92.png\" alt=\"Figure2\" title=\"Figure2\">\u003C\u002Fp>\n\u003Cp>You may notice the transaction is actually going through the L1 first then interpreted by the L2 indexer. That is exactly how Kasplex L2 works, where the L1 finalises the data, before the L2 reads the transaction then transits the state.\u003C\u002Fp>\n\u003Ch2 id=\"Comparing-Kasplex-L2-with-Bitcoin-Inscriptions\">Comparing Kasplex L2 with Bitcoin Inscriptions\u003C\u002Fh2>\n\u003Cp>To contextualize Kasplex L2, it’s useful to compare it with Bitcoin Inscriptions, specifically BRC-20, a popular mechanism for token issuance on Bitcoin. Both systems aim to extend the functionality of UTXO-based blockchains by leveraging the L1 for data storage and ordering, but they differ in their implementation and goals.\u003C\u002Fp>\n\u003Cp>Similarities\u003C\u002Fp>\n\u003Cp>Data Embedding in L1: Both Kasplex L2 and BRC-20 embed data in L1 transactions. BRC-20 uses Bitcoin’s Tapscript (enabled by the SegWit upgrade) to store token metadata, typically through a three-step process: commit (hash of the data), reveal (the data itself), and spend (token transfer). Kasplex L2 embeds EVM bytecode in the payload of Kaspa L1 transactions, achieving a similar goal of anchoring L2 operations to the L1.\u003C\u002Fp>\n\u003Cp>L1 as the Source of Truth: In both cases, the L1 provides the canonical ordering of operations. BRC-20 relies on Bitcoin’s blockchain to sequence token transfers, while Kasplex L2 uses Kaspa’s BlockDAG to order smart contract executions.\u003C\u002Fp>\n\u003Cp>Indexer Dependency: Both systems depend on off-chain indexers for processing. BRC-20 indexers parse Bitcoin transactions to track token balances, while Kasplex L2’s indexer executes EVM bytecode to maintain smart contract states.\u003C\u002Fp>\n\u003Cp>Differences\u003C\u002Fp>\n\u003Cp>Implementation Efficiency: BRC-20’s three-step process is a workaround for Bitcoin’s rigid protocol, which was not designed to support L2 operations. Kasplex L2 benefits from Kaspa’s more cooperative L1, allowing data to be embedded in a single transaction payload, reducing complexity and overhead.\u003C\u002Fp>\n\u003Cp>Performance Considerations: Bitcoin’s throughput is limited to approximately 7 TPS, with blocks produced every 10 minutes on average, making Inscriptions slow and costly. Kaspa’s 10 BPS upgrade provides a significant performance advantage, enabling Kasplex L2 to handle higher transaction volumes more efficiently.\u003C\u002Fp>\n\u003Cp>Scope and Functionality: BRC-20 is narrowly focused on token issuance and transfers, whereas Kasplex L2 supports full EVM compatibility, allowing for complex smart contracts such as DeFi protocols or NFT marketplaces.\u003C\u002Fp>\n\u003Cp>Protocol Flexibility: Bitcoin’s conservative design prioritizes immutability, requiring L2 solutions to work around its constraints. Kaspa’s L1, while still a UTXO system, is more flexible, enabling tighter integration with L2 solutions like Kasplex.\u003C\u002Fp>\n\u003Cp>This comparison highlights a key insight: while the conceptual approach of using the L1 for data and sequencing is shared, Kasplex L2 leverages Kaspa’s architectural advantages to achieve greater efficiency and broader functionality compared to Bitcoin Inscriptions.\u003C\u002Fp>\n\u003Ch2 id=\"Evaluating-Kasplex-L2-Strengths-and-Limitations\">Evaluating Kasplex L2: Strengths and Limitations\u003C\u002Fh2>\n\u003Cp>From a technical research perspective, Kasplex L2 presents several notable strengths and limitations, which we evaluate below.\u003C\u002Fp>\n\u003Cp>Strengths\u003C\u002Fp>\n\u003Cp>Functional Expansion: Kasplex L2 successfully extends Kaspa’s capabilities by enabling EVM-compatible smart contracts, supporting use cases such as decentralized applications and tokenization that are otherwise infeasible on the L1.\u003C\u002Fp>\n\u003Cp>Efficient Use of L1: By relying on Kaspa’s BlockDAG for sequencing and data availability, Kasplex L2 minimizes the computational burden on the L2, focusing solely on execution. This design aligns well with Kaspa’s high-throughput architecture.\u003C\u002Fp>\n\u003Cp>Public Verifiability: Since all transactions are recorded on the L1, the execution of smart contracts on Kasplex L2 can be independently verified by re-running the EVM bytecode in the canonical order, ensuring transparency.\u003C\u002Fp>\n\u003Cp>Limitations and Risks\u003C\u002Fp>\n\u003Cp>Indexer Trust: The L2’s indexer plays a critical role in executing bytecode and maintaining state. However, there is a risk of indexer misbehavior, such as presenting an incorrect state (e.g., a falsified Merkle root) while maintaining a separate, hidden state. Mitigating this requires a decentralized indexer network, potentially with economic incentives or penalties, which has not yet been implemented.\u003C\u002Fp>\n\u003Cp>Reorganization Challenges: Kaspa’s BlockDAG, while efficient, is susceptible to reorganizations in recent blocks due to its parallel block production. This can force the L2 to revert and re-execute transactions, introducing complexity. \u003C\u002Fp>\n\u003Ch2 id=\"Implications-for-UTXO-Based-Blockchains\">Implications for UTXO-Based Blockchains\u003C\u002Fh2>\n\u003Cp>Kasplex L2 offers a case study in scaling programmability for UTXO-based blockchains, with potential lessons for systems like Bitcoin. Both Kaspa and Bitcoin face similar constraints in supporting smart contracts due to their UTXO models, but Kaspa’s higher throughput and more flexible L1 design provide a more favorable environment for L2 solutions.\u003C\u002Fp>\n\u003Cp>For Bitcoin, Kasplex L2’s design suggests several areas of exploration:\u003C\u002Fp>\n\u003Cp>Relayer Integration: The proxied submission mechanism demonstrates how EVM-compatible tools can be integrated with a UTXO blockchain, a concept that could be adapted for Bitcoin L2 solutions like BitVM.\u003C\u002Fp>\n\u003Cp>Indexer-Based Execution: The use of an indexer to execute off-chain computations while anchoring data on the L1 aligns with Bitcoin’s Inscription model and could inspire new approaches to scaling programmability.\u003C\u002Fp>\n\u003Cp>From a research perspective, Kasplex L2 serves as a valuable experiment, demonstrating how architectural differences between UTXO blockchains (e.g., throughput, protocol flexibility) impact the feasibility of L2 solutions. Its findings can inform the design of scaling solutions across the blockchain ecosystem, particularly for systems prioritizing decentralization and security over native programmability.\u003C\u002Fp>\n\u003Ch2 id=\"Conclusion\">Conclusion\u003C\u002Fh2>\n\u003Cp>Kasplex L2 is a technically sound implementation of a based rollup, enabling EVM-compatible smart contracts on Kaspa by leveraging its L1 for sequencing and data availability. Our analysis highlights its efficiency in utilizing Kaspa’s high-throughput BlockDAG, as well as its ability to extend functionality through EVM compatibility. We view Kasplex L2 as a significant contribution to the study of L2 solutions for UTXO-based blockchains. Its comparison with Bitcoin Inscriptions reveals both shared principles and the impact of L1 design on L2 feasibility. For researchers and developers, Kasplex L2 offers a lens through which to explore the intersection of scalability, programmability, and decentralization in blockchain systems\u003C\u002Fp>\n\u003Ch2 id=\"Reference\">Reference\u003C\u002Fh2>\n\u003Cp>Kasplex Github. [Online]. Available: \u003Ca target=\"_blank\" rel=\"noopener\" href=\"https:\u002F\u002Fgithub.com\u002Fkasplex\u002Findexer-executor\">https:\u002F\u002Fgithub.com\u002Fkasplex\u002Findexer-executor\u003C\u002Fa>\u003Cbr>Kaspa Research, “On the Design of Based zk-Rollups over Kaspa’s UTXO-Based DAG Consensus,” 2024. [Online]. Available: \u003Ca target=\"_blank\" rel=\"noopener\" href=\"https:\u002F\u002Fresearch.kas.pa\u002Ft\u002Fon-the-design-of-based-zk-rollups-over-kaspas-utxo-based-dag-consensus\u002F208\">https:\u002F\u002Fresearch.kas.pa\u002Ft\u002Fon-the-design-of-based-zk-rollups-over-kaspas-utxo-based-dag-consensus\u002F208\u003C\u002Fa>\u003C\u002Fp>\n\u003Cp>A big shout-out to our researcher @ZorrotChen. Thank you for contributing to this article!\u003C\u002Fp>","\u002Fmedia\u002Fmovebit\u002F2025\u002F05\u002F53cb218effcd84232c837c60e5bbc2af.png","As blockchain technology evolves, scalability and programmability remain critical challenges, particularly for blockchains using the UTXO model. Kaspa, a Layer 1 blockchain leveraging a BlockDAG structure, achieves high throughput but lacks native smart contract functionality, a limitation shared by other UTXO-based sy","2025-05-20T03:15:00Z","9 min read","BitsLab Research | Kasplex L2 A Light-Weight Based Rollup Solution on Kaspa cover image",{"slug":90,"category":7,"categoryLabel":6,"subcategoryLabel":17,"authorName":18,"title":91,"excerpt":92,"contentHtml":93,"coverUrl":94,"seoTitle":91,"seoDescription":95,"seoImageUrl":94,"publishedAt":96,"updatedAt":77,"readTime":97,"cover":94,"hasCover":26,"coverAlt":98},"a-deep-dive-analysis-a-2024-comprehensive-review-of-technological-innovations-and-security-events-in-the-move-ecosystem-20241204","A Deep Dive Analysis A 2024 Comprehensive Review of Technological Innovations and Security Events in the Move Ecosystem","The Move programming language has brought disruptive changes to blockchain smart contracts with its unique resource management design, security-first architecture, and modular development model. Driven by these innovations, the emerging public blockchains have achieved high performance and scalability breakthroughs through technologies such as parallel execution, object-oriented design, and horizontal scaling. However, as the Move ecosystem expands, its security has also faced challenges in real-world applications.","\u003Cp>The Move programming language has brought disruptive changes to blockchain smart contracts with its unique resource management design, security-first architecture, and modular development model. Driven by these innovations, the emerging public blockchains have achieved high performance and scalability breakthroughs through technologies such as parallel execution, object-oriented design, and horizontal scaling. However, as the Move ecosystem expands, its security has also faced challenges in real-world applications. The denial-of-service vulnerabilities exposed in 2023 and 2024 highlight the delicate balance between complexity and security in blockchain systems. Through timely patching of vulnerabilities, strengthening permission management, and advancing code verification, the Move ecosystem is gradually building a blockchain development model that balances technological innovation with security, laying the foundation for the future evolution of blockchain technology.\u003C\u002Fp>\n\u003Ch2 id=\"Move-Programming-Language-A-Revolutionary-Force-in-Blockchain-Smart-Contracts\">Move Programming Language: A Revolutionary Force in Blockchain Smart Contracts\u003C\u002Fh2>\n\u003Cp>Before delving into the specific technological innovations within the Move ecosystem, it is essential first to understand the foundation of this ecosystem—the Move programming language. As a disruptive force in blockchain smart contract development, Move redefines the possibilities of resource management and modular development and provides a solid technological backbone for public chain projects through its security-first design philosophy. In the following, we will analyze the unique advantages of the Move language and how related blockchains, through innovative smart contract architectures, successfully showcase the vast potential of the Move ecosystem.\u003C\u002Fp>\n\u003Cp>The Move language was originally developed by Facebook (now Meta) for the Diem (Libra) project to address the performance and security bottlenecks inherent in traditional smart contract languages. The design of Move emphasizes the clarity and security of resources, ensuring that every state change on the blockchain is controllable. This innovative programming language offers the following key advantages:\u003C\u002Fp>\n\u003Cp>Resource Management Model: Move treats assets as resources, making them non-replicable or destructible. This unique resource management model helps avoid common smart contract issues such as double-spending or accidental asset destruction.\u003C\u002Fp>\n\u003Cp>Modular Design: Move allows smart contracts to be built modularly, improving code reusability and reducing development complexity.\u003C\u002Fp>\n\u003Cp>High Security: Move incorporates numerous built-in security checks at the language level to prevent common security vulnerabilities, such as reentrancy attacks.\u003C\u002Fp>\n\u003Cp>In summary, with its innovative design principles and powerful technical advantages, the Move programming language has set a new standard for blockchain smart contract development. By treating assets as non-replicable or destructible resources, Move significantly enhances the security of resource management. Its modular design brings greater flexibility and efficiency to developers. Furthermore, the built-in security features help safeguard against various common vulnerabilities.\u003C\u002Fp>\n\u003Ch2 id=\"Security-Events-in-the-Move-Ecosystem\">Security Events in the Move Ecosystem\u003C\u002Fh2>\n\u003Cp>As the Move ecosystem evolves, it faces numerous security challenges alongside its technological innovations. From the core design of its virtual machine to the specific mechanisms of network operations, security issues have become critical factors affecting the ecosystem’s stability and development. In recent years, two significant security events have occurred within the Move ecosystem—an infinite recursion vulnerability in 2023 and a memory pool DoS vulnerability in 2024. These incidents exposed potential risks in the system and underscored the importance of security research and vulnerability remediation within the ecosystem. Thanks to close collaboration between development teams and third-party security organizations, these issues were promptly addressed, laying a solid foundation for the further development of the Move ecosystem.\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"\u002Fmedia\u002Fmovebit\u002F2024\u002F12\u002Ff51d3b4c3729f53d4006e129f66721cf.png\" alt=\"Figure1\" title=\"Figure1\">\u003C\u002Fp>\n\u003Ch2 id=\"Details-of-Specific-Security-Events\">Details of Specific Security Events\u003C\u002Fh2>\n\u003Cp>In June 2023, a critical denial-of-service (DoS) vulnerability was discovered in the Move virtual machine, which could lead to the complete collapse of public blockchains such as Sui and Aptos or even force a hard fork. After identifying the vulnerability, security researcher Poetyellow disclosed the related details. However, the Move virtual machine development team had independently discovered the issue earlier and spent more than a month resolving it.\u003C\u002Fp>\n\u003Cp>This vulnerability was an infinite recursion flaw. In programming languages, infinite recursive function calls causing stack overflows are a common type of DoS vulnerability, and even secure languages like Rust are not immune to it.\u003C\u002Fp>\n\u003Cp>In September 2024, MoveBit successfully discovered and helped fix a memory pool DoS vulnerability in the Aptos network, rated as High severity. This vulnerability stemmed from an inadequate transaction eviction mechanism in the memory pool, potentially causing up to 90% of valid transactions to be rejected by nodes. The Aptos team resolved the issue in version v1.19.1 and publicly acknowledged MoveBit’s contribution in the official release notes.\u003C\u002Fp>\n\u003Cp>From the infinite recursion vulnerability to the memory pool DoS issue, these security incidents within the Move ecosystem reveal the potential risks that come with technological innovation. At the same time, they demonstrate the ecosystem’s ability to respond quickly and implement effective fixes. However, resolving security challenges cannot rely solely on addressing individual incidents. It requires systematic optimization at the level of overall architecture and language design. Next, we will explore critical aspects such as resource management, permission control, and code auditing to analyze how the Move ecosystem balances technological advancements and security protections.\u003C\u002Fp>\n\u003Ch2 id=\"Security-Observations-in-the-Move-Ecosystem\">Security Observations in the Move Ecosystem\u003C\u002Fh2>\n\u003Cp>The emergence of the Move programming language has introduced a groundbreaking approach to smart contract development in blockchain ecosystems, primarily applied in public chains like Aptos and Sui. The design of Move was originally centered around security, utilizing resource management, static type systems, and memory management to prevent common vulnerabilities. However, as the ecosystem continues to expand, specific security areas require ongoing attention:\u003C\u002Fp>\n\u003Cp>Resource Management and State Consistency: Move’s unique resource types allow developers to manage asset ownership within contracts explicitly. While this reduces risks such as asset loss or reentrancy attacks, the complexity of resource transfer and management logic can introduce new errors. Ensuring the effectiveness of resource lifecycle management and avoiding resource transfer vulnerabilities is crucial.\u003C\u002Fp>\n\u003Cp>Permission Control and Access Management: The modular development approach of the Move ecosystem facilitates component reuse, but controlling access permissions to modules is critical. Developers must strictly limit the permissions for sensitive operations, ensuring the functionality and access levels of modules are appropriately managed to prevent attackers from exploiting high-privilege contract modules.\u003C\u002Fp>\n\u003Cp>Security Auditing and Code Verification: The complexity of Move code increases the difficulty of auditing, necessitating continuous security audits and formal verification to ensure the code is free from overflows, logical errors, and other common risks. Standardized audit processes and regular code reviews are essential for maintaining the long-term security of the Move ecosystem.\u003C\u002Fp>\n\u003Cp>In conclusion, the introduction of the Move programming language represents a significant revolution in the field of blockchain smart contracts. Its unique resource management model, security-first design philosophy, and modular development approach address multiple bottlenecks in performance, security, and flexibility faced by traditional smart contract languages. By treating assets as non-replicable or indestructible resources, Move effectively avoids common issues such as double-spending. At the same time, its modular design enables developers to reuse code more efficiently and reduce complexity. On public blockchains like Aptos and Sui, which are based on the Move language, innovative technologies such as parallel execution engines, object-oriented design, and horizontal scaling have brought unprecedented performance and scalability to blockchain systems. This marks Move’s ecosystem as a technological leap forward in blockchain development.\u003C\u002Fp>\n\u003Cp>However, security issues have gradually emerged as the Move ecosystem rapidly expands. Two critical security incidents in 2023 and 2024—an infinite recursion vulnerability and a memory pool DoS vulnerability—highlight the delicate balance between complexity and security in blockchain systems. Nevertheless, the Move ecosystem has demonstrated strong capabilities in addressing security challenges through timely vulnerability fixes, enhanced permission management, and advancements in code verification. As a leading security auditing company, BitsLab remains committed to providing comprehensive security assurance and safeguarding the healthy development of the Move ecosystem and the blockchain industry. By ensuring the parallel progression of technological innovation and security measures, BitsLab continues to contribute to the future evolution of blockchain technology.\u003C\u002Fp>\n\u003Ch2 id=\"About-BitsLab\">About BitsLab\u003C\u002Fh2>\n\u003Cp>BitsLab is a security organization dedicated to safeguarding and building emerging Web3 ecosystems, with a vision to become a highly respected Web3 security institution recognized by the industry and its users. It operates three sub-brands: MoveBit, ScaleBit, and TonBit. BitsLab focuses on infrastructure development and security audits for emerging ecosystems, covering but not limited to Sui, Aptos, TON, Linea, BNB Chain, Soneium, Starknet, Movement, Monad, Internet Computer, and Solana. Additionally, BitsLab demonstrates profound expertise in auditing various programming languages, including Circom, Halo2, Move, Cairo, Tact, FunC, Vyper, and Solidity.\u003C\u002Fp>\n\u003Cp>As a leader in blockchain security, BitsLab has provided security auditing services for flagship projects such as Movement, Aptos Framework, Catizen, Synthetix, Tether, Cetus, UniSat, Nervos CKB, iZUMI Finance, and Pontem. To date, BitsLab has delivered over 400 security solutions, audited over 400,000 lines of code, and safeguarded assets worth over $8 billion, providing security for over 2 million users worldwide. These achievements reflect BitsLab’s commitment to high-quality audit services and its role in setting security standards for the blockchain industry.\u003C\u002Fp>\n\u003Cp>Furthermore, the BitsLab team comprises top vulnerability research experts who have repeatedly won international CTF awards and discovered critical vulnerabilities in well-known projects such as TON, Aptos, Sui, Nervos, OKX, and Cosmos. BitsLab will continue to focus on advancing security in the Web3 space, contributing to the healthy development of emerging ecosystems.\u003C\u002Fp>\n\u003Cp>Visit BitsLab’s official website: \u003Ca target=\"_blank\" rel=\"noopener\" href=\"https:\u002F\u002Fbitslab.xyz\u002F\">https:\u002F\u002Fbitslab.xyz\u002F\u003C\u002Fa>\u003Cbr>BitsLab’s official Twitter: \u003Ca target=\"_blank\" rel=\"noopener\" href=\"https:\u002F\u002Fx.com\u002F0xbitslab\">https:\u002F\u002Fx.com\u002F0xbitslab\u003C\u002Fa>\u003Cbr>Join the official Telegram community: \u003Ca target=\"_blank\" rel=\"noopener\" href=\"https:\u002F\u002Ft.me\u002FBitsLabHQ\">https:\u002F\u002Ft.me\u002FBitsLabHQ\u003C\u002Fa>\u003Cbr>BitsLab brand resources: \u003Ca target=\"_blank\" rel=\"noopener\" href=\"https:\u002F\u002Fsomber-throne-617.notion.site\u002FBitsLab-Brand-Assets-12e7c2e0096880e58c9fd49f0852f49b\">https:\u002F\u002Fsomber-throne-617.notion.site\u002FBitsLab-Brand-Assets-12e7c2e0096880e58c9fd49f0852f49b\u003C\u002Fa>\u003Cbr>BitsLab Sub-brand Official Websites:\u003Cbr>MoveBit: \u003Ca target=\"_blank\" rel=\"noopener\" href=\"https:\u002F\u002Fwww.movebit.xyz\u002F\">https:\u002F\u002Fwww.movebit.xyz\u002F\u003C\u002Fa>\u003Cbr>TonBit: \u003Ca target=\"_blank\" rel=\"noopener\" href=\"https:\u002F\u002Fwww.tonbit.xyz\u002F\">https:\u002F\u002Fwww.tonbit.xyz\u002F\u003C\u002Fa>\u003Cbr>ScaleBit: \u003Ca target=\"_blank\" rel=\"noopener\" href=\"https:\u002F\u002Fwww.scalebit.xyz\u002F\">https:\u002F\u002Fwww.scalebit.xyz\u002F\u003C\u002Fa>\u003C\u002Fp>","\u002Fmedia\u002Fmovebit\u002F2024\u002F12\u002F9446aae112ebbd00ff4d0e8a131f8dee.jpg","The Move programming language has brought disruptive changes to blockchain smart contracts with its unique resource management design, security-first architecture, and modular development model. Driven by these innovations, the emerging public blockchains have achieved high performance and scalability breakthroughs thr","2024-12-04T03:15:00Z","8 min read","A Deep Dive Analysis A 2024 Comprehensive Review of Technological Innovations and Security Events in the Move Ecosystem cover image",{"slug":100,"category":7,"categoryLabel":6,"subcategoryLabel":60,"authorName":18,"title":101,"excerpt":102,"contentHtml":103,"coverUrl":104,"seoTitle":101,"seoDescription":102,"seoImageUrl":104,"publishedAt":105,"updatedAt":77,"readTime":56,"cover":104,"hasCover":26,"coverAlt":106},"movebit-discovers-and-helps-fix-vulnerability-in-sui-cross-chain-protocol-20241012","MoveBit Discovers and Helps Fix Vulnerability in Sui Cross-Chain Protocol","MoveBit , a sub-brand of BitsLab, is a security team focused on the Move ecosystem, building the standard and delivering security audits for secure Move ecosystem.","\u003Ch1 id=\"Sui-Vulnerabilities-Explanation\">\u003Cstrong>Sui Vulnerabilities Explanation\u003C\u002Fstrong>\u003C\u002Fh1>\n\u003Cp>Sui[3] is the first Layer 1 blockchain designed from scratch as a permissionless platform. It’s renowned for its scalability, security focus, and rich on-chain assets. Compared to other blockchains, Sui maintains low gas fees even under high network traffic due to its scalability. Move design emphasizes security, mitigating issues like reentrancy vulnerabilities and forged token approvals. By supporting dynamic NFTs and gaming economies, Sui provides a platform for developers to innovate in Web3 development. The Sui Development Kit empowers developers to build applications without constraints, preparing for the arrival of the next billion users.\u003C\u002Fp>\n\u003Cp>To expand its ecosystem, Sui incorporates various experimental features such as Native Bridge, zkLogin with Multisig, zkLogin providers, Random beacon, and Enums.\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"\u002Fmedia\u002Fmovebit\u002F2024\u002F10\u002F0ea9d87c87a834abd6f8ddee5bede352.png\" alt=\"Banner\" title=\"Banner\">\u003C\u002Fp>\n\u003Ch1 id=\"Background\">\u003Cstrong>Background\u003C\u002Fstrong>\u003C\u002Fh1>\n\u003Cp>  In the evolving landscape of Ethereum’s solo endeavors, major platforms continuously innovate to bolster their capabilities, fostering the development of the DeFi ecosystem. Within this context, various types of non-standard ERC20 tokens have emerged, finding widespread utility within the ecosystem. These tokens include fee-on-transfer tokens, Approval Race Protections tokens, Revert on Zero Value Transfers tokens, Missing Return Values tokens, among others.\u003C\u002Fp>\n\u003Cp>Missing Return Values tokens pose a unique challenge due to their deviation from the standard ERC20 protocol. Some tokens, such as USDT, BNB, and OMG, do not return a boolean value on ERC20 methods as required by the ERC20 standard. According to the ERC20 standard, checking the return value is a prerequisite[4]. However, tokens like USDT, which lack return values, can encounter errors when attempting to verify the success of a transfer.\u003C\u002Fp>\n\u003Cp>Therefore, special handling is necessary to address this issue.\u003C\u002Fp>\n\u003Ch1 id=\"The-vulnerabilities\">\u003Cstrong>The vulnerabilities\u003C\u002Fstrong>\u003C\u002Fh1>\n\u003Ch3 id=\"Funds-transferred-through-the-cross-chain-bridge-using-USDT-will-remain-permanently-frozen-in-the-protocol\">Funds transferred through the cross-chain bridge using USDT will remain permanently frozen in the protocol\u003C\u002Fh3>\n\u003Cp>SuiBridge is a cross-chain bridge contract that facilitates users to deposit tokens supported by the protocol and withdraw them on another chain. According to the BridgeConfig contract, we find that the supported tokens include Sui, WBTC, WETH, USDC, USDT, and ETH as shown below.\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"\u002Fmedia\u002Fmovebit\u002F2024\u002F10\u002Fd60190b0a02ba5f26a2cf727bc151123.png\" alt=\"Code1\" title=\"Code1\">\u003C\u002Fp>\n\u003Cp>The function bridgeERC20() allows users to deposit supported tokens to be bridged to a specified destination chain. Let’s delve into the code of bridgeERC20() as as shown in the following code snippet:\u003C\u002Fp>\n\u003Cp>  The protocol first verifies on line 137 whether the token being deposited is supported by the protocol. Then, on lines 142-145, it checks whether the bridge contract has an allowance to transfer the token. Next, on line 148, it calls token.transferFrom() to transfer the tokens from the user to the vault. Subsequently, on line 151, it converts the amount of tokens based on their precision on the Sui chain. Finally, it emits a log, facilitating the Committee of Sui validators to verify and process the cross-chain bridge messages. Tokens such as Sui, WBTC, WETH, USDC, and USDT can all be deposited using this function call.\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"\u002Fmedia\u002Fmovebit\u002F2024\u002F10\u002F71c1364bd597ff90cc48291876cd0ec8.png\" alt=\"Code2\" title=\"Code2\">\u003C\u002Fp>\n\u003Cp>If a user transfers assets cross-chain from the Sui chain to the Ethereum (ETH) chain, they can use the \u003Ccode>transferBridgedTokensWithSignatures()\u003C\u002Fcode> function to move tokens to a specified receiving address. If the tokens are ERC20, the protocol will invoke the \u003Ccode>vault.transferERC20()\u003C\u002Fcode> function to transfer the tokens from the vault to the target address. Let’s take a look at the \u003Ccode>vault.transferERC20()\u003C\u002Fcode> function as described in the following code snippet.\u003C\u002Fp>\n\u003Cp>In the function, the protocol first obtains the token address at line 41. Then, it calls token.transfer() at line 44 to transfer the tokens to the target address, returning a boolean value. Finally, at line 47, the protocol checks that this boolean value must be true.\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"\u002Fmedia\u002Fmovebit\u002F2024\u002F10\u002F0b378d44b416dbb72bcf613221cc8832.png\" alt=\"Code3\" title=\"Code3\">\u003C\u002Fp>\n\u003Cp>As we previously analyzed, for tokens like USDT, there is no return value upon successful transfer. Consequently, if USDT is being extracted from the protocol, token.transfer() will return void, resulting in a failed execution. Consequently, USDT cannot be withdrawn from the protocol, and there is no function within the protocol to extract funds, leading to the permanent freezing of funds within the protocol.\u003C\u002Fp>\n\u003Cp>Regarding such issues, OpenZeppelin[5] has already addressed and developed a library named safeERC20 to mitigate this problem. Therefore, it is recommended to utilize OpenZeppelin’s safeTransfer() function for withdrawing cross-chain funds.\u003C\u002Fp>\n\u003Ch1 id=\"Timeline-amp-Mitigation\">** Timeline &amp; Mitigation\u003C\u002Fh1>\n\u003Cp>  On April 1st, the MoveBit team discovered a vulnerability related to asset freezing and promptly submitted it to Sui via the HackenProof platform\u003C\u002Fp>\n\u003Cp>On April 17th, we submitted another vulnerability.\u003C\u002Fp>\n\u003Cp>On April 19th, following communication between the Mysten team and engineers, both issues were confirmed.\u003C\u002Fp>\n\u003Cp>On May 10th, this issue was resolved.\u003Ca target=\"_blank\" rel=\"noopener\" href=\"https:\u002F\u002Fgithub.com\u002FMystenLabs\u002Fsui\u002Fcommit\u002Fd01026e2f8c9128ff29f52811b507df745c38a86\">https:\u002F\u002Fgithub.com\u002FMystenLabs\u002Fsui\u002Fcommit\u002Fd01026e2f8c9128ff29f52811b507df745c38a86\u003C\u002Fa>\u003C\u002Fp>\n\u003Ch1 id=\"Reference\">** Reference:\u003C\u002Fh1>\n\u003Cp>1.\u003Ca target=\"_blank\" rel=\"noopener\" href=\"https:\u002F\u002Fhackenproof.com\u002F\">https:\u002F\u002Fhackenproof.com\u002F\u003C\u002Fa>\u003C\u002Fp>\n\u003Cp>2.\u003Ca target=\"_blank\" rel=\"noopener\" href=\"https:\u002F\u002Fabout.google\u002Fappsecurity\u002F\">https:\u002F\u002Fabout.google\u002Fappsecurity\u002F\u003C\u002Fa>\u003C\u002Fp>\n\u003Cp>3.\u003Ca target=\"_blank\" rel=\"noopener\" href=\"https:\u002F\u002Fdocs.sui.io\u002F\">https:\u002F\u002Fdocs.sui.io\u002F\u003C\u002Fa>\u003C\u002Fp>\n\u003Cp>4.\u003Ca target=\"_blank\" rel=\"noopener\" href=\"https:\u002F\u002Fhackenproof.com\u002Fredirect?url=https:\u002F\u002Feips.ethereum.org\u002FEIPS\u002Feip-20\">https:\u002F\u002Feips.ethereum.org\u002FEIPS\u002Feip-20\u003C\u002Fa>\u003C\u002Fp>\n\u003Cp>5.\u003Ca target=\"_blank\" rel=\"noopener\" href=\"https:\u002F\u002Fgithub.com\u002FOpenZeppelin\u002Fopenzeppelin-contracts\u002Fblob\u002F52c36d412e8681053975396223d0ea39687fe33b\u002Fcontracts\u002Ftoken\u002FERC20\u002Futils\u002FSafeERC20.sol#L36\">https:\u002F\u002Fgithub.com\u002FOpenZeppelin\u002Fopenzeppelin-contracts\u002Fblob\u002F52c36d412e8681053975396223d0ea39687fe33b\u002Fcontracts\u002Ftoken\u002FERC20\u002Futils\u002FSafeERC20.sol#L36\u003C\u002Fa>\u003C\u002Fp>","\u002Fmedia\u002Fmovebit\u002F2024\u002F10\u002F22ce78c5cf109a310635fb8d23b09eee.jpg","2024-10-12T03:15:00Z","MoveBit Discovers and Helps Fix Vulnerability in Sui Cross-Chain Protocol cover image",{"slug":108,"category":7,"categoryLabel":6,"subcategoryLabel":60,"authorName":18,"title":109,"excerpt":110,"contentHtml":111,"coverUrl":112,"seoTitle":109,"seoDescription":113,"seoImageUrl":112,"publishedAt":114,"updatedAt":77,"readTime":67,"cover":112,"hasCover":26,"coverAlt":115},"bluefin-vulnerabilities-explanation-1","Bluefin Vulnerabilities Explanation","An in-depth analysis of the security vulnerabilities found in Bluefin, a decentralized perpetual trading platform powered by the Sui blockchain. Discover issues like share manipulation, improper permission control, oracle price handling, and ownership transfer risks, along with proposed solutions to enhance platform security and reliability.","\u003Cp>\u003Cimg src=\"\u002Fmedia\u002Fmovebit\u002F2024\u002F05\u002Fa7ed5215e1f6e1c888cf4b5ec6905847.jpg\" alt=\"Bluefin-Vulnerabilities-Explanation\" title=\"Bluefin Vulnerabilities Explanation\">\u003C\u002Fp>\n\u003Ch2 id=\"Overview-of-the-Bluefin-Audit-Contest\">Overview of the Bluefin Audit Contest\u003C\u002Fh2>\n\u003Cp>On February 13, 2024, \u003Ca target=\"_blank\" rel=\"noopener\" href=\"https:\u002F\u002Fbluefin.io\u002F\">Bluefin\u003C\u002Fa> (Bluefin is a decentralized perpetual trading platform powered by the Sui blockchain) hosted the first-ever audit contest targeting Move smart contracts on the \u003Ca target=\"_blank\" rel=\"noopener\" href=\"https:\u002F\u002Fhackenproof.com\u002F\">Hackenproof\u003C\u002Fa> platform. Two security researchers from Movebit actively participated in this contest and achieved satisfactory results.\u003C\u002Fp>\n\u003Cp>Overall, the audit revealed 2 high-risk, 3 medium-risk, and several low-risk and informational-level issues. Among them, \u003Cstrong>Movebit identified 1 high-risk, 3 medium-risk, as well as several low-risk and informational-level issues during the audit.\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"\u002Fmedia\u002Fmovebit\u002F2024\u002F05\u002F7c192a85242171eb446e0c6d0d8124ea.png\" alt=\"Movebit-participated-in-HackenProof-contest-and-achieved-amazing-results\" title=\"Movebit participated in HackenProof contest and achieved amazing results\">\u003C\u002Fp>\n\u003Ch2 id=\"About-Bluefin\">About Bluefin\u003C\u002Fh2>\n\u003Cp>Bluefin is a decentralized order book exchange designed for both professional traders and first-time traders, focusing on security, transparency, and redefining the user experience with on-chain trading platforms. Powered by the Sui blockchain, Bluefin ensures sub-second completion of trades and reflects them instantly on their user interface, providing users with high-performance trading while bridging the experience between Web2 and Web3. Bluefin will continue to leverage the best available technology to drive excellence in performance, security, and transparency, combining a wallet-less trading experience backed by leading companies such as Polychain, SIG, and Brevan Howard.\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"\u002Fmedia\u002Fmovebit\u002F2024\u002F05\u002F40bf538fce51457b4d725ede13f43a3d.png\" alt=\"Bluefin\" title=\"Bluefin\">\u003C\u002Fp>\n\u003Ch2 id=\"Analysis-of-Bluefin-Security-Issues\">Analysis of Bluefin Security Issues\u003C\u002Fh2>\n\u003Cp>Bluefin is dedicated to providing users with a fast and secure trading experience. However, in the pursuit of this goal, it also faces some potential security vulnerabilities and technical challenges. In the following sections, we will conduct a detailed analysis of the security issues found in the Bluefin platform to take appropriate improvement measures, ensuring that users’ funds are adequately protected and thereby constructing a more secure and trustworthy trading environment.\u003C\u002Fp>\n\u003Ch3 id=\"1-Share-Manipulation\">1. Share Manipulation\u003C\u002Fh3>\n\u003Cp>Bluefin provides an additional bluefin_vault module that allows users to interact with vaults. Among them, the deposit_to_vault function allows users to deposit funds into vaults and receive a certain amount of shares, while the withdraw_from_vault function allows users to destroy a certain amount of shares to redeem their funds. The design of this module is similar to Ethereum’s ERC4626 model, which is a standard for tokenized treasuries.\u003C\u002Fp>\n\u003Cp>However, Bluefin’s current deposit and withdrawal functions suffer from the classic share manipulation vulnerability found in the ERC4626 model. Let’s take a look at the section of the bluefin_vault.deposit_to_vault function regarding share calculation.\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"\u002Fmedia\u002Fmovebit\u002F2024\u002F05\u002F1fc58dc2c7942abb69958283cf5bb4d8.png\" alt=\"Bluefin-Share-Manipulation-1\" title=\"Bluefin Share Manipulation 1\">\u003C\u002Fp>\n\u003Cp>As shown in the code snippet at line 248, the user’s share quantity is calculated as follows: the number of tokens deposited by the user multiplied by the total number of shares in the current Vault divided by the total balance of tokens in the Vault. Then, as shown in the code snippet at line 275, the user’s funds are recharged into the margin_bank through the deposit_to_bank function of the margin_bank.\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"\u002Fmedia\u002Fmovebit\u002F2024\u002F05\u002F4558507f95daa7d9b635505c17df5636.png\" alt=\"Bluefin-Share-Manipulation-2\" title=\"Bluefin Share Manipulation 2\">\u003C\u002Fp>\n\u003Cp>When a user first deposits funds, both vault_total_balance and total_shares are 0. At this point, the user’s share quantity equals the amount they deposit, i.e., shares = amount. This provides an opportunity for attackers to manipulate shares. It’s worth noting that there’s a check in place to ensure that shares must be greater than 0, which mitigates share manipulation attacks to some extent, but this defense measure is still insufficient.\u003C\u002Fp>\n\u003Cp>Let’s describe the entire process of a share manipulation attack using an example involving user Alice and attacker Bob:\u003C\u002Fp>\n\u003Col>\n\u003Cli>\n\u003Cp>Suppose the deposited token is SUI. Initially, the attacker deposited 1 MIST to obtain 1 share.\u003C\u002Fp>\n\u003C\u002Fli>\n\u003Cli>\n\u003Cp>User Alice attempts to deposit 2 SUI into the contract. If Alice tries to deposit at this point, she will receive (1 share * 2 SUI) \u002F 1 MIST = 2e9 shares.\u003C\u002Fp>\n\u003C\u002Fli>\n\u003Cli>\n\u003Cp>However, before Alice’s transaction, attacker Bob directly transfers 1 SUI via the margin_bank::deposit_to_bank function.\u003C\u002Fp>\n\u003C\u002Fli>\n\u003Cli>\n\u003Cp>This results in Alice’s current deposited share calculation as (1 share * 2 SUI) \u002F (1 SUI + 1 MIST).\u003C\u002Fp>\n\u003C\u002Fli>\n\u003Cli>\n\u003Cp>Due to truncation, the calculated result is 1 share, passing the aforementioned check that shares must be greater than 0.\u003C\u002Fp>\n\u003C\u002Fli>\n\u003Cli>\n\u003Cp>Finally, attacker Bob withdraws SUI via the withdraw_from_vault function. 1 share is now worth approximately 1.5 SUI because the contract holds 3 SUI + 1 MIST, but the contract has only minted 2 shares.\u003C\u002Fp>\n\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Cp>To address the aforementioned share manipulation issue, several solutions can be considered:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\n\u003Cp>Revert if the amount received is not within a slippage tolerance (Add slip protection if possible).\u003C\u002Fp>\n\u003C\u002Fli>\n\u003Cli>\n\u003Cp>The deployer should deposit enough assets into the vault such that doing this inflation attack would be too expensive.\u003C\u002Fp>\n\u003C\u002Fli>\n\u003Cli>\n\u003Cp>Add virtual liquidity to the vault so the pricing behaves as if the vault had been deployed with enough assets.\u003C\u002Fp>\n\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch3 id=\"2-Improper-Permission-Control\">2. Improper Permission Control\u003C\u002Fh3>\n\u003Cp>Bluefin invokes the validate_unique_tx function for each transaction to verify its uniqueness, such as trade, liquidate, deposit_to_bank, withdraw_from_bank, etc. Below is the process of creating a transaction hash, ensuring randomness through the object::new(ctx) shown in the code snippet at line 513.\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"\u002Fmedia\u002Fmovebit\u002F2024\u002F05\u002Fefc054518a4778cd8a580dbe9f49c472.png\" alt=\"Bluefin-Improper-Permission-Control-1\" title=\"Bluefin Improper Permission Control 1\">\u003C\u002Fp>\n\u003Cp>Bluefin verifies the uniqueness of each transaction by passing in a transaction hash, as shown in the code snippet below.\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"\u002Fmedia\u002Fmovebit\u002F2024\u002F05\u002F206bdd793057a4896e74b2ea915f4208.png\" alt=\"Bluefin-Improper-Permission-Control-2\" title=\"Bluefin Improper Permission Control 2\">\u003C\u002Fp>\n\u003Cp>The validate_unique_tx function plays a crucial role in ensuring the uniqueness of the tx_hash for each transaction within the system and relies on the continuously growing sequencer. However, the function lacks permission control and is publicly visible, meaning anyone can pass in any tx_hash and store it in the sequencer. This could lead to several potential issues:\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\n\u003Cp>Effective resource management and prevention of unrestricted execution are crucial for maintaining protocol security and gas efficiency. Attackers can freely transmit garbage data to the sequencer, increasing its capacity and causing gas consumption for transactions referencing the sequencer to increase. Sui has some limitations on transactions and the data they use, such as maximum size and the number of objects used. If the size of the sequencer grows indefinitely, it could lead to DoS attacks, rendering transactions unable to execute and funds unable to be withdrawn.\u003C\u002Fp>\n\u003C\u002Fli>\n\u003Cli>\n\u003Cp>Malicious attackers can front-run by prematurely passing tx_hash to the sequencer, causing normal transactions to fail because the transaction hash already exists in the sequencer.\u003C\u002Fp>\n\u003C\u002Fli>\n\u003Cli>\n\u003Cp>If the frontend relies on tx_hash to parse transactions, it may encounter issues such as transactions being unable to be parsed.\u003C\u002Fp>\n\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>To prevent these attacks, it is recommended to add permission control to the validate_unique_tx function or change its visibility to friend.\u003C\u002Fp>\n\u003Ch3 id=\"3-The-issue-with-Oracle-Price-Handling\">3. The issue with Oracle Price Handling\u003C\u002Fh3>\n\u003Ch4 id=\"1-Oracle-does-not-check-outdated-prices\">1) Oracle does not check outdated prices\u003C\u002Fh4>\n\u003Cp>In the Bluefin exchange contract, many functions such as trade, liquidate, deleverage, etc., call the perpetual.update_oracle_price function to fetch prices from Pyth and update them in the perpetual contract for subsequent calculations and validation.\u003C\u002Fp>\n\u003Cp>As we know, \u003Ca target=\"_blank\" rel=\"noopener\" href=\"https:\u002F\u002Fpyth.network\u002F\">Pyth\u003C\u002Fa> is an oracle providing real-time prices to the chain. On Sui, Pyth updates the latest prices every few minutes.\u003C\u002Fp>\n\u003Cp>As shown in the code snippet at line 217, the protocol calls the pyth.get_price_unsafe function to fetch prices from Pyth.\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"\u002Fmedia\u002Fmovebit\u002F2024\u002F05\u002F023e740c7989f2eb141d5dbd0828de5f.png\" alt=\"Bluefin-Oracle-does-not-check-outdated-prices-1\" title=\"Bluefin Oracle does not check outdated prices 1\">\u003C\u002Fp>\n\u003Cp>Let’s take a look at the get_price_unsafe code together. As shown in lines 379 to 384 below, \u003Ca target=\"_blank\" rel=\"noopener\" href=\"https:\u002F\u002Fgithub.com\u002Fpyth-network\u002Fpyth-crosschain\u002Fblob\u002Fe7bf47a18e2d9a9d983214342540691c1bada52e\u002Ftarget_chains\u002Fsui\u002Fcontracts\u002Fsources\u002Fpyth.move#L379-L384\">Pyth’s official documentation\u003C\u002Fa> explicitly states that the function’s returned price is not guaranteed to be the latest. If the latest available price is needed, the get_price_no_older_than function should be used to fetch the price not later than the given time.\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"\u002Fmedia\u002Fmovebit\u002F2024\u002F05\u002F52a71a6e7a47b3a4a45538ad6a5731dc.png\" alt=\"Bluefin-Oracle-does-not-check-outdated-prices-2\" title=\"Bluefin Oracle does not check outdated prices 2\">\u003C\u002Fp>\n\u003Cp>Therefore, using pyth.get_price_unsafe in the protocol may result in obtaining outdated prices, leading to inaccurate subsequent calculations and validation, thereby affecting the normal operation of the protocol.\u003C\u002Fp>\n\u003Ch4 id=\"2-Oracle-does-not-check-for-zero-values\">2) Oracle does not check for zero values\u003C\u002Fh4>\n\u003Cp>Similarly, in the process of fetching prices from Pyth as described above, the protocol did not consider the scenario where the price is zero. Let’s take a look at how Pyth handles positive and negative values for prices. Since Move does not support native negative numbers, Pyth adds an additional field called negative to represent positive and negative values. The value 0 is represented as (0, false), meaning that 0 is non-negative, indicating that in Pyth, a price of 0 is considered positive.\u003Cbr>\u003Cimg src=\"\u002Fmedia\u002Fmovebit\u002F2024\u002F05\u002Fff10d099d1810d3954da8fd1cb6440d0.png\" alt=\"Bluefin-Oracle-does-not-check-zero-values-1\" title=\"Bluefin Oracle does not check for zero values 1\">\u003C\u002Fp>\n\u003Cp>Currently, the protocol checks whether the obtained price is non-negative using get_magnitude_if_positive, but it does not consider the case where the price is zero, meaning that we can obtain a value of 0 as a price. Additionally, Pyth may also return a price of 0. Referencing the diagram below:\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"\u002Fmedia\u002Fmovebit\u002F2024\u002F05\u002F40e5b3680a69e2105b7e609cc62d3cdb.png\" alt=\"Bluefin-Oracle-does-not-check-zero-values-2\" title=\"Bluefin Oracle does not check for zero values 2\">\u003C\u002Fp>\n\u003Cp>To prevent Pyth from returning a price of 0, it is recommended to add a check for non-zero values for prices.\u003C\u002Fp>\n\u003Ch3 id=\"4-Dangerous-Single-Step-Ownership-Transfer\">4. Dangerous Single-Step Ownership Transfer\u003C\u002Fh3>\n\u003Cp>Within the current Bluefin protocol, there are several instances of ownership transfer operations, such as changing the exchange’s administrator permissions. Administrators play a critical role in the current protocol, such as setting guardians for the exchange and designating operators with certain permissions. However, the existing implementation of administrator permission transfer poses potential security risks. The current implementation directly transfers the management of the exchange to a new address, as shown in the diagram below. While this method is straightforward, it carries risks in the event of specifying an incorrect address or malicious takeover. The single-step ownership transfer process lacks validation or confirmation steps for the new administrator, which could result in unintentionally losing control of the exchange’s management.\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"\u002Fmedia\u002Fmovebit\u002F2024\u002F05\u002F1a77630ac32163ab15794916234ed7c5.png\" alt=\"Bluefin-Dangerous-Single-Step-Ownership-Transfer\" title=\"Bluefin Dangerous Single-Step Ownership Transfer\">\u003C\u002Fp>\n\u003Cp>To mitigate these risks, it is recommended to adopt a two-step ownership transfer mechanism to manage the exchange’s administration. This mechanism involves two steps: the current administrator proposes the transfer and the new administrator confirms acceptance. Through this process, it can be ensured that the new administrator is willing and able to accept the management role, providing an additional layer of security and error prevention.\u003C\u002Fp>\n\u003Cp>The implementation steps are as follows:\u003C\u002Fp>\n\u003Col>\n\u003Cli>\n\u003Cp>Ownership Transfer Proposal: The current administrator calls a method to propose a new administrator. This operation records the proposed new administrator’s address in the contract state but does not immediately transfer the rights.\u003C\u002Fp>\n\u003C\u002Fli>\n\u003Cli>\n\u003Cp>Ownership Acceptance: The proposed new administrator must explicitly accept the role by calling a separate contract method. Only after this operation is executed, the management permissions will be transferred.\u003C\u002Fp>\n\u003C\u002Fli>\n\u003C\u002Fol>\n\u003Ch3 id=\"5-Failure-to-Distinguish-between-Limit-Orders-and-Market-Orders\">5. Failure to Distinguish between Limit Orders and Market Orders\u003C\u002Fh3>\n\u003Cp>In the current Bluefin trading platform, there are two common order types: limit orders and market orders. In the evaluator contract, as shown in the code snippet at lines 214-233 below, the set_max_qty_limit function is used to set the maximum transaction quantity for limit orders, while the set_max_qty_market function sets the maximum transaction quantity for market orders.\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"\u002Fmedia\u002Fmovebit\u002F2024\u002F05\u002Fe243cddaaa584c560d18c34df4f33973.png\" alt=\"Bluefin-Failure-to-Distinguish-between-Limit-Orders-and-Market-Orders-1\" title=\"Bluefin Failure to Distinguish between Limit Orders and Market Orders 1\">\u003C\u002Fp>\n\u003Cp>However, when checking the transaction quantity, there is no distinction between limit orders and market orders. The verify_min_max_qty_checks function is used to verify that the transaction quantity must be greater than the minimum and less than the maximum. However, this function simultaneously checks both the maximum transaction quantity for limit orders and market orders when executing transaction orders. This results in the maximum quantity check for market orders also being applied to limit orders, which is unreasonable.\u003C\u002Fp>\n\u003Cp>\u003Cimg src=\"\u002Fmedia\u002Fmovebit\u002F2024\u002F05\u002Fddbc23e321d4f78e0fd284a91a9da72a.png\" alt=\"Bluefin-Failure-to-Distinguish-between-Limit-Orders-and-Market-Orders-2\" title=\"Bluefin Failure to Distinguish between Limit Orders and Market Orders 2\">\u003C\u002Fp>\n\u003Cp>To improve this situation, it is recommended to differentiate between limit orders and market orders in the verify_min_max_qty_checks function and perform the corresponding maximum transaction quantity checks separately. This ensures that correct quantity checks are applied to different types of orders, enhancing the security and effectiveness of the trading platform.\u003C\u002Fp>\n\u003Ch2 id=\"Summary\">Summary\u003C\u002Fh2>\n\u003Cp>Through a thorough analysis of the issues identified during the Bluefin audit contest, we have proposed solutions and improvement suggestions for each issue to ensure that the Bluefin platform can provide a secure and efficient trading experience. Each issue has been carefully analyzed here, and corresponding strategies have been proposed. With these improvements, we believe that Bluefin will be able to further solidify its position in the decentralized perpetual trading field and provide users with a safer and more reliable trading environment.\u003C\u002Fp>\n\u003Ch2 id=\"About-MoveBit\">About MoveBit\u003C\u002Fh2>\n\u003Cp>MoveBit, a subsidiary brand of BitsLab, is a blockchain security team that specializes in the Move ecosystem. It’s at the forefront of utilizing cutting-edge Formal Verification techniques. The team comprises security professionals with extensive experience in both academia and enterprise. As one of the earliest contributors to the Move ecosystem, MoveBit has collaborated closely with Move developers to establish security standards for secure Move applications, making it the most secure Web3 destination.\u003C\u002Fp>\n\u003Cp>\u003Ca target=\"_blank\" rel=\"noopener\" href=\"https:\u002F\u002Fwww.movebit.xyz\u002F?type=getAudit\">Requests a quote\u003C\u002Fa>\u003C\u002Fp>\n\u003Cul>\n\u003Cli>\u003Ca target=\"_blank\" rel=\"noopener\" href=\"https:\u002F\u002Fwww.movebit.xyz\u002F\">Website\u003C\u002Fa>\u003C\u002Fli>\n\u003Cli>\u003Ca target=\"_blank\" rel=\"noopener\" href=\"https:\u002F\u002Ftwitter.com\u002Fmovebit_\">Twitter\u003C\u002Fa>\u003C\u002Fli>\n\u003Cli>\u003Ca target=\"_blank\" rel=\"noopener\" href=\"https:\u002F\u002Ft.me\u002F+eTM3__HuoaZjN2Q0\">Telegram\u003C\u002Fa>\u003C\u002Fli>\n\u003C\u002Ful>","\u002Fmedia\u002Fmovebit\u002F2024\u002F05\u002F7c192a85242171eb446e0c6d0d8124ea.png","An in-depth analysis of the security vulnerabilities found in Bluefin, a decentralized perpetual trading platform powered by the Sui blockchain. Discover issues like share manipulation, improper permission control, oracle price handling, and ownership transfer risks, along with proposed solutions to enhance platform se","2024-05-16T10:00:00Z","Bluefin Vulnerabilities Explanation cover image",1,10,1792635791890]