Auditing Smart Contracts on Sui

Key security considerations for Sui developers, with real findings from Certora’s audits and formal verification work.

In short: Sui uses an object-centric model in which assets and application state are represented by objects, and Move defines how those objects can be created, transferred, and modified. A Sui audit checks what a function does, which objects it accepts, how authorization is enforced, and whether relationships between objects remain valid across transactions.. Certora's Sui reviews have identified issues involving capability substitution, share accounting, liquidation logic, and cross-chain message processing.

In Certora's Suilend verification, a finding showed how a relayer could substitute an ObligationOwnerCap when returning a borrowed capability. The receipt was returned, but it was not checked against the specific obligation capability originally borrowed. This left a gap between satisfying the transaction's structural requirements and preserving the intended authorization. The report records the finding as acknowledged. The Suilend report describes the issue and the recommended check.

How does Sui's object model affect security?

Sui programs are written in Move, but their state model differs from the storage model used by the Ethereum Virtual Machine (EVM). Rather than storing application state in a contract's own storage, Sui represents assets and application data as objects with unique IDs, types, owners, and versions. Transactions take objects as inputs and produce updated or newly created objects as outputs. The Sui object model documentation explains these mechanics.

Ownership determines how an object can be used. Address-owned objects are controlled by a specific address. Shared objects can be accessed by transactions from different addresses, subject to the rules implemented by the Move package. Immutable objects cannot be modified. Objects can also be wrapped inside other objects, making their access dependent on the containing object.

These distinctions affect the security assumptions of the application. A shared liquidity pool, for example, can be passed to a transaction by any caller. The fact that the caller can reference the pool does not mean they are authorized to perform every operation on it. The Move function must enforce any additional permissions required for the operation.

An audit should follow the important objects through their lifecycle: creation, initialization, transfer, mutation, wrapping, and destruction. It should also check whether every operation receives objects that belong to the intended protocol, user, market, or position.

How should authorization and capabilities be audited on Sui?

Sui's ownership model provides important protections, but protocols often need permissions beyond ordinary object ownership. Administrative actions, minting, pausing, upgrades, and access to a user's lending position may require additional authorization.

Move applications commonly represent these permissions using capability objects. A function can require a particular capability as an argument, making possession of that object part of the authorization model. This is often preferable to relying only on the transaction sender, especially when an operation must be authorized for a specific market or position.

The critical question is whether the capability authorizes the operation that receives it. A capability may be valid in isolation but associated with a different object than the one being modified. If a protocol accepts a capability without checking that relationship, it can enforce the wrong permission.

The Suilend finding illustrates this problem. Its strategy wrapper had a return_obligation_cap function that accepted an ObligationOwnerCap without verifying that it matched the capability originally borrowed through a BorrowReceipt. A malicious relayer could borrow the user's real capability, create a new empty obligation to obtain another capability, and return the empty capability to satisfy the receipt. The report recommended binding the receipt to the original obligation ID and checking that ID when the capability is returned. The report lists the finding as acknowledged.

This is why an audit must check more than whether a capability exists or a receipt is consumed. It needs to establish that the same authority, associated with the intended object, is returned or used as required.

The Sui Move best practices recommend explicit capabilities for privileged functions and checking the relationship between a capability and the object it governs.

What does Move's type system guarantee, and what does it leave to the application?

Move's type system and resource model prevent several classes of mistakes. Values cannot be copied or discarded arbitrarily when their types do not permit those operations, and the language enforces rules around resource handling. Sui's object model also makes ownership explicit.

These guarantees do not establish that the program's business logic is correct.

For example, a generic function may accept a pool parameterized by a particular coin type and also accept a separate asset index or configuration value. The type system can ensure that the pool contains the expected coin type, but it does not automatically ensure that the asset index refers to that same asset. If the function uses the index for accounting and the pool for transferring funds, a mismatch can cause the protocol to account for one asset while moving another.

The same principle applies to public functions. A function being callable from another module or package does not mean it should be available without additional authorization. An audit should review visibility modifiers such as public and public(package), check which functions can mutate sensitive state, and establish whether their callers are intended to have that access.

Move's explicit references also deserve attention. When working with mutable references, assigning a reference is not the same as assigning the value it points to. Confusing these operations can cause a function to update the wrong field while still compiling and executing. This is especially important in accounting and authorization code, where a small state-update error can change future protocol behavior.

The review should therefore cover both language-level safety and application-level correctness. The former constrains how code can behave; the latter determines whether that behavior matches the protocol's requirements.

How should shared objects and transaction composition be reviewed?

Sui supports Programmable Transaction Blocks (PTBs), which allow multiple operations to be composed into a single transaction. Objects produced by one operation can be used by later operations in that transaction. This makes it possible to combine protocol actions without requiring a separate transaction for every step.

The audit needs to consider the complete sequence, not just each function in isolation. A receipt may be created by one function and consumed by another. A coin may be split, passed into a protocol operation, and merged with another balance. A capability may be borrowed temporarily and returned later. The security property depends on the relationships preserved throughout that sequence.

Consider a flash loan or another operation that requires a receipt to be returned before the transaction completes. A receipt can enforce that a required step occurs, but it does not automatically prove that the step was performed against the correct pool, position, or asset. If the receipt does not bind the operation to the original object, a caller may satisfy the structural requirement while violating the intended economic condition.

Shared objects introduce another consideration. Because multiple callers can reference them, their entry points must enforce the intended authorization and state-transition rules. The review should identify which functions can change shared state, which objects they depend on, and whether every valid transaction sequence preserves the protocol's assumptions.

The Sui documentation on Programmable Transaction Blocks and object ownership provide the relevant execution model.

How can rounding and accounting bugs affect Sui protocols?

Move's arithmetic rules do not remove the need to verify economic calculations. Lending protocols, vaults, and staking systems maintain relationships between underlying assets, shares, debt, collateral, fees, and exchange rates. Those relationships must remain valid after every supported operation.

In Certora's Suilend verification, the deposit calculation for cTokens involved two rounding steps. The implementation first calculated an exchange ratio with truncated decimal precision, then used that ratio to calculate the number of cTokens to mint. Rounding down the intermediate ratio could result in slightly more cTokens being minted than the deposit warranted, diluting existing holders. The report marked this finding as fixed and recommended calculating the result with a single multiplication and division, followed by one rounding step.

The Suilend review also identified an issue in which incremental updates to an obligation's health aggregates could diverge from recomputing those aggregates from the final position state. Because the calculations used rounded arithmetic, a borrow or withdrawal could leave the obligation appearing healthy until a later refresh recomputed its values and revealed that it was unhealthy. The report records this issue as fixed.

These examples show why auditing individual calculations is not enough. The important property is the relationship between the complete state before and after an operation. A calculation that looks reasonable in isolation may still create excess shares, understate debt, or allow an unhealthy position to pass a safety check.

For lending protocols, an audit should examine collateral valuation, borrowing limits, interest accrual, liquidation thresholds, repayment, and the effect of rounding on small positions. For vaults and staking systems, it should verify that share issuance and redemption remain consistent with the underlying assets and fees.

What should an audit check about oracle data in Sui protocols?

Oracle-dependent protocols must establish that the price used for an operation is valid for that operation. This includes checking freshness, handling invalid or missing data, and ensuring that changes to the configured feed are reflected in the price actually used by the protocol.

The Suilend report identified an issue in which an oracle timestamp in the future could bypass stale-price protections. It also found that changing a price feed did not update the reserve price, leaving stale price data. Both findings were marked fixed in the report.

The broader lesson is that checking a timestamp or validating a feed address is not sufficient on its own. The audit should trace how the price is obtained, validated, stored, refreshed, and consumed by deposits, borrows, withdrawals, and liquidations.

It should also check what happens when an update fails or the data is outside the accepted range. A protocol must not silently use an invalid price, and it should not become permanently unable to perform an otherwise valid operation because its update path cannot recover from stale data.

What can go wrong in cross-chain protocols built on Sui?

A bridge must preserve the meaning of a message as it moves between chains. That includes the message contents, signatures, nonces, validator permissions, and the conditions under which a transfer or governance action can execute.

Certora's Sui Bridge security assessment reviewed both the Move contracts on Sui and the Solidity contracts on Ethereum, with formal verification on both sides. One medium-severity finding concerned the treatment of blocklisted validators. The Sui side skipped a blocklisted validator's signature when calculating approval thresholds but stored the full signature array. The EVM side subsequently rejected signatures from blocklisted validators, so messages that had already been approved on Sui could fail when claimed on Ethereum and require manual intervention. The report records this finding as acknowledged.

This is a consistency problem across the bridge's components. Each side applied a rule that made sense locally, but the combined behavior was not consistent. Similar issues can arise when message formats, nonce handling, thresholds, or replay protections differ between implementations.

An audit should trace a message from creation through signature collection, verification, execution, and final asset transfer. It should check that both sides agree on what has been authorized and that a failure at any stage cannot result in duplicate execution, unauthorized transfers, or permanently stuck funds.

How should package upgrades and privileged configuration be reviewed on Sui?

Published Sui packages are immutable, but a package can be upgraded through Sui's upgrade mechanism when the required authority and policy permit it. The UpgradeCap controls the ability to publish a newer package version, subject to the applicable upgrade policy.

This makes upgrade authority part of the protocol's trust model. An audit should establish who controls the capability, which upgrades are permitted, and whether the upgrade policy provides the guarantees users expect. It should also examine privileged configuration changes, including changes to oracle feeds, risk parameters, supported assets, fees, and pause controls.

Configuration changes can alter the meaning of otherwise valid state. For example, changing a price feed without refreshing the stored reserve price can leave the protocol using stale data. Changing risk parameters can also affect existing positions, including their borrowing capacity and liquidation conditions.

The review should ask whether an authorized administrator can make a change, whether that change preserves the protocol’s safety properties, and how its effects are communicated and monitored.

See the Sui package upgrade documentation for the platform's upgrade model.

Which invariants matter for Sui protocols?

An invariant is a property that must remain true across every valid state transition. The relevant properties depend on the protocol, but they should describe its authorization and economic requirements rather than merely restating what individual functions do.

For a lending protocol, an obligation must remain associated with the correct owner and market. Borrowing and withdrawal operations must preserve collateral and solvency requirements. Liquidations must reduce or otherwise correctly account for debt and collateral, and rounding must not create unbacked claims.

For a vault, the value of outstanding shares must remain consistent with the assets backing them, within defined rounding bounds. For a bridge, every executed message must satisfy the required authorization and replay protections, and the same message must not be processed inconsistently across chains.

For protocols using capabilities or receipts, the capability must authorize the intended object and operation. Returning a receipt or consuming a resource must not allow a caller to substitute an unrelated object and bypass the original requirement.

These properties should be checked across sequences of operations, including edge cases and state transitions that are easy to overlook in unit tests. A property that holds after a deposit but fails after a withdrawal, liquidation, refresh, or configuration change is not preserved by the protocol.

How should Sui programs be tested and formally verified?

Tests should cover successful operations as well as invalid objects, unauthorized callers, mismatched asset types, stale oracle data, boundary values, and sequences that change state over time. For lending protocols, tests should include deposits, borrows, repayments, withdrawals, liquidations, and refresh operations in different orders. For receipt-based flows, they should test whether a receipt can be returned with a capability or object different from the one originally supplied.

Formal verification can establish that specified properties hold for the modeled implementation under the assumptions of the verification. Certora's Suilend report describes verification of the Move contracts against rules written by the Certora team, alongside the issues identified during that process. The Sui Bridge report also documents formal verification of both the Move and EVM components.

The guarantees depend on the properties specified and the code and assumptions included in the verification scope. A proof of one accounting property does not establish that authorization, oracle handling, upgrade governance, and cross-chain execution are all correct. The specification must cover the properties that matter to the protocol.

What should a team building on Sui prepare before an audit?

Before an audit, a team should document the intended ownership and authorization model, the capabilities required for privileged operations, and the relationships between the objects used by each important function. It should also define the protocol's economic invariants, supported asset types, oracle update behavior, and package upgrade policy.

For systems that use receipts or temporary capabilities, the documentation should explain what each receipt proves and which object or operation it must be tied to. For cross-chain protocols, it should describe how messages are authorized, replay-protected, and processed on each chain.

These details give the audit a clear baseline for checking whether the implementation matches the protocol's intended behavior.

Further reading

Frequently asked questions

  • What is a Sui smart contract audit? A review of Move packages, the objects they operate on, the authorization they enforce, and the state transitions they permit. For DeFi protocols, the audit also checks accounting, oracle handling, and the properties that must hold across deposits, borrows, withdrawals, liquidations, and other operations.
  • How does auditing Sui differ from auditing EVM contracts? Sui uses an object-centric model in which transactions explicitly operate on objects, and Move defines how those objects can be used. The audit therefore pays particular attention to object ownership, capabilities, object relationships, and the composition of operations within transactions.
  • Does Move eliminate smart contract vulnerabilities? No. Move's type system and resource model prevent certain classes of errors, but they do not guarantee that application logic is correct. Authorization gaps, mismatched object relationships, accounting errors, stale oracle data, and incorrect cross-chain assumptions can still create vulnerabilities.
  • Does Certora audit Sui Move contracts? Yes. Certora has reviewed and formally verified Sui Move contracts, including the Suilend lending protocol and the Sui Bridge. The published reports describe the scope, verification work, and findings for each engagement. Its public reports are on the Certora reports page.


Get every blog post delivered

Certora Logo
logologo
Terms of UsePrivacy Policy