Sui Move Security
Make invalid transitions unrepresentable where possible and reject the rest before mutation.
Target repository instructions, accepted design records, pinned toolchain behavior, and published compatibility commitments take precedence over this standard's examples.
Build the threat model
- Before code, name every asset; safety, conservation, liveness, and exit
invariant; authority and worst-case compromise; untrusted caller,
composition, and dependency; and required failure behavior. The threat model
is complete only when every changed transition and asset has been mapped.
- Trace every public or entry function, same-PTB composition, and reachable
multi-transaction sequence in execution order. The trace is complete when
each guard, read, proposed value, postcondition, mutation, asset movement,
event, and return is accounted for.
- Apply every relevant rule below and each triggered reference to every traced
path. Reconcile each asset type in its own conservation ledger.
- Use the proof obligations below as the completion gate, reporting every
unresolved assumption as a security gap.
For each public or entry function, same-PTB composition, and reachable
multi-transaction sequence, prove all three properties:
- A valid pre-state produces a valid post-state.
- An abort commits no partial effects.
- Returned objects, capabilities, witnesses, receipts, and other values cannot
be recombined to violate an invariant.
Security is complete only when every callable path and composition preserves
the package's safety, conservation, authority, liveness, and exit invariants.
Before any irreversible or state-gating transition, prove that every required
exit, settlement, cleanup, retry, cancellation, authority rotation, and
recovery operation remains reachable. Reject a transition that can leave
shared state permanently paused, locked, full, orphaned, version-incompatible,
or dependent on an unavailable capability, object, or external system. Permit
that outcome only for a deliberate terminal state with every obligation already
discharged.
Fail fast and mutate last
Abort on the cheapest decisive condition. Exhaust checks available from current information before allocation, cryptography, dependency work, mutation, asset movement, or event construction. Use this order:
- package version, pause, or an active seam lock;
- cheap lifecycle, input, identity, deadline, and authorization checks, including rejection of identical type arguments for roles that must differ;
- bounds, available-balance, and other economic checks that need no proposed value;
- required read-only external data, signature work, deserialization, or expensive math;
- compute each fallible proposed final value once before mutation, naming it when checks or later mutation reuse it;
- validate all fallible postconditions, including minimum output and maximum input, against the proposed values;
- mutate state and move assets;
- emit the final-state event;
- return owned values.
The numbered order applies when dependency calls are read-only or can be last.
A result-bearing composable handoff is a deliberate exception. Use this order:
- finish every local check;
- acquire the narrowest lock or issue a linear receipt;
- interact;
- validate exact receipts and balance deltas;
- commit core state and asset movements;
- clear the lock;
- emit.
Do not postpone a check that could have preceded an effect or interaction.
Guard order is observable API. Test overlapping invalid conditions. Abort rollback does not justify avoidable late checks: early failure saves gas, preserves diagnostic precedence, and shrinks the reasoning surface.
Reject a setter whose new value equals the current value before mutation, with its own stable error, so every emitted old/new pair records a real transition. A non-mutating authorization or discovery fact may still emit the value it newly commits.
Express authority with types
- Use a typed capability or witness instead of an address check for privileged operations.
- Inventory every authority constructor, issuance, transfer, share, receive, rotation, revocation, and destruction path. Prove each use is bound to the exact object and domain, and that abilities match intended custody.
- Verify a revocable cap against live registry state before issuing a drop-only witness.
- Let the concern-owning module validate that witness locally.
- Keep a global cap minimal. Store target IDs only in a deliberately per-instance cap.
- Separate root authority from routine administration.
- Use delayed, explicit, test-covered root rotation.
- Add cancellation or recipient acceptance when the threat model requires it.
- Before burning, renouncing, or irreversibly handing off the last root or
upgrade authority, prove successor usability and required exit and recovery
liveness.
- Never infer broad authority from unrelated object possession or transaction sender alone.
- Do not pass overlapping capabilities to one setter or transition.
- Give capability holders a production lifecycle for safe destruction or revocation when stranded objects are possible.
- Reject zero addresses for recipients and authorities unless the zero address has an explicit protocol meaning.
- For a permissionless irreversible transition, never take economic parameters
from caller choice. Derive them from accepted stored policy, derived state, a sealed
adapter type, or a compiled value that is itself the accepted immutable
policy. Otherwise fail closed.
If the contract verifies off-chain signatures
- Bind authorization to the exact action, actor or beneficiary, target object or original type, expiry, and any domain not already fixed by a dedicated key.
- Reject malformed or non-canonical messages before verification. Prevent replay, and make third-party submission fail harmlessly or produce only the approved effect.
- If one key spans actions, deployments, or networks, use explicit domain separation and document the shared compromise scope.
Prevent replay with linearity
- Prefer consuming a unique authorization resource over storing
claimed: bool or a parallel nonce.
- Validate first, consume the resource, construct the result, emit the final-state event, then return the result.
- Use non-copyable, non-droppable payloads for migration, flash, or settlement handoffs.
- Require the exact sealed witness type to redeem a cross-package handoff.
- When admitting a witness by
TypeName, reject primitive and vector types and prove its constructor is sealed in the approved module; TypeName alone cannot prove construction rights.
- Treat events as index facts, never replay guards.
- For a repeatable signed operation, consume a nonce, digest, or linear authorization exactly once and define bounded storage, eviction, and cleanup. Permit intentional replay only when it is documented and safe.
Bound state and work
- Bound every persistent collection with a named protocol constant, and record the reachable maximum plus intentional slack.
- Bound every loop whose input can grow on chain.
- Check duplicates before consuming capacity.
- Define behavior at capacity. When bounded work is optional, prefer a safe liveness-preserving fallback over aborting the user's primary transition.
- Test empty, full, first-over-capacity, duplicate, removal, and re-addition cases.
- Avoid public inputs that cause unbounded deserialization, iteration, event size, or dynamic-field growth.
- Keep pending work and retry state bounded and explicitly releasable.
Load external-input guidance when applicable
For deadlines, time-dependent authorization, slippage, oracles, price feeds, or
random outcomes, read
Time, oracles, and randomness
completely before designing, changing, or reviewing the transition.
Load DeFi guidance when applicable
For shares, vaults, liquid staking, farms, rewards, AMMs, lending,
liquidations, or other DeFi accounting, read
DeFi security completely before designing,
changing, or reviewing the transition. Apply it with this skill's invariant,
fail-fast, custody, oracle, and external-seam rules.
Preserve conservation and custody
Write and test one operation-specific identity per asset type, never a mixed-unit equation, derived from:
assets in = assets out + reserves + accrued fees + pending custody + explicitly burned amount
- Keep reserves, fees, pending burns, allocations, residuals, and claims separate when their owner or terminal treatment differs.
- For every admitted asset, document its original type, mint and supply
authority, deny, pause, or action restrictions, units, and authoritative
balance delta.
- Reject an asset whose controls can break mandatory settlement or exit
invariants unless an accepted admission decision records and bounds that risk
explicitly.
- Use actual balances as authority, never event-only counters or SDK previews.
- Reconcile after every operation and multi-operation sequence.
- Make burn, disposal, refund, fee, residual, and rounding treatment explicit.
- Do not call disposal a burn unless native supply authority confirms destruction.
- Reject unexpected residuals or clamps that could conceal a broken invariant.
Defend external seams
- Perform every locally available check before external reads, calls, or asset handoffs.
- Validate returned object identity, original type, package, pair, tier, units, amounts, actual balance deltas, liquidity, price deviation, freshness, and residual bounds.
- Keep external dependency and failure surfaces in adapters, not core.
- Do not cargo-cult an EVM reentrancy guard onto ordinary statically resolved Move calls. Threat-model PTB composition and flash, hot-potato, or explicit callback-like handoffs; lock only the smallest shared seam until exact receipt and repayment validation completes.
- Do not support an external venue whose required payment or custody model violates core invariants.
- Verify deployed bytecode and ABI; a local link stub proves type compatibility only.
Define pause behavior
- Define pause scope exactly and preserve user exits and mandatory settlement
unless the design explicitly rejects them.
- Let emergency authority reduce risk, not seize, reprice, or rewrite user
accounting.
Load upgrade guidance when applicable
Before changing or reviewing publication, upgrades, package-capability custody,
operational versioning, shared-state migration, or dependency relinking, read
Upgrade security completely. Also read it
when old and new package versions can both reach shared protocol state changed
by the task.
Protect sensitive material
- Keep secrets, private transaction material, and deployment credentials out
of source, logs, fixtures, and summaries.
1---2name: sui-move-security3description: Security for privileged, stateful, economic, cryptographic, shared-object, and external-integration Sui Move code. Use when designing, changing, or reviewing transitions, authority, replay, bounded work, custody, DeFi, time, oracles, randomness, pauses, dependencies, or upgrades.4---56# Sui Move Security78Make invalid transitions unrepresentable where possible and reject the rest before mutation.910Target repository instructions, accepted design records, pinned toolchain behavior, and published compatibility commitments take precedence over this standard's examples.1112## Build the threat model13141. Before code, name every asset; safety, conservation, liveness, and exit15 invariant; authority and worst-case compromise; untrusted caller,16 composition, and dependency; and required failure behavior. The threat model17 is complete only when every changed transition and asset has been mapped.182. Trace every public or entry function, same-PTB composition, and reachable19 multi-transaction sequence in execution order. The trace is complete when20 each guard, read, proposed value, postcondition, mutation, asset movement,21 event, and return is accounted for.223. Apply every relevant rule below and each triggered reference to every traced23 path. Reconcile each asset type in its own conservation ledger.244. Use the proof obligations below as the completion gate, reporting every25 unresolved assumption as a security gap.2627For each public or entry function, same-PTB composition, and reachable28multi-transaction sequence, prove all three properties:2930- A valid pre-state produces a valid post-state.31- An abort commits no partial effects.32- Returned objects, capabilities, witnesses, receipts, and other values cannot33 be recombined to violate an invariant.3435Security is complete only when every callable path and composition preserves36the package's safety, conservation, authority, liveness, and exit invariants.3738Before any irreversible or state-gating transition, prove that every required39exit, settlement, cleanup, retry, cancellation, authority rotation, and40recovery operation remains reachable. Reject a transition that can leave41shared state permanently paused, locked, full, orphaned, version-incompatible,42or dependent on an unavailable capability, object, or external system. Permit43that outcome only for a deliberate terminal state with every obligation already44discharged.4546## Fail fast and mutate last4748Abort on the cheapest decisive condition. Exhaust checks available from current information before allocation, cryptography, dependency work, mutation, asset movement, or event construction. Use this order:49501. package version, pause, or an active seam lock;512. cheap lifecycle, input, identity, deadline, and authorization checks, including rejection of identical type arguments for roles that must differ;523. bounds, available-balance, and other economic checks that need no proposed value;534. required read-only external data, signature work, deserialization, or expensive math;545. compute each fallible proposed final value once before mutation, naming it when checks or later mutation reuse it;556. validate all fallible postconditions, including minimum output and maximum input, against the proposed values;567. mutate state and move assets;578. emit the final-state event;589. return owned values.5960The numbered order applies when dependency calls are read-only or can be last.61A result-bearing composable handoff is a deliberate exception. Use this order:62631. finish every local check;642. acquire the narrowest lock or issue a linear receipt;653. interact;664. validate exact receipts and balance deltas;675. commit core state and asset movements;686. clear the lock;697. emit.7071Do not postpone a check that could have preceded an effect or interaction.7273Guard order is observable API. Test overlapping invalid conditions. Abort rollback does not justify avoidable late checks: early failure saves gas, preserves diagnostic precedence, and shrinks the reasoning surface.7475Reject a setter whose new value equals the current value before mutation, with its own stable error, so every emitted old/new pair records a real transition. A non-mutating authorization or discovery fact may still emit the value it newly commits.7677## Express authority with types7879- Use a typed capability or witness instead of an address check for privileged operations.80- Inventory every authority constructor, issuance, transfer, share, receive, rotation, revocation, and destruction path. Prove each use is bound to the exact object and domain, and that abilities match intended custody.81- Verify a revocable cap against live registry state before issuing a drop-only witness.82- Let the concern-owning module validate that witness locally.83- Keep a global cap minimal. Store target IDs only in a deliberately per-instance cap.84- Separate root authority from routine administration.85- Use delayed, explicit, test-covered root rotation.86- Add cancellation or recipient acceptance when the threat model requires it.87- Before burning, renouncing, or irreversibly handing off the last root or88 upgrade authority, prove successor usability and required exit and recovery89 liveness.90- Never infer broad authority from unrelated object possession or transaction sender alone.91- Do not pass overlapping capabilities to one setter or transition.92- Give capability holders a production lifecycle for safe destruction or revocation when stranded objects are possible.93- Reject zero addresses for recipients and authorities unless the zero address has an explicit protocol meaning.94- For a permissionless irreversible transition, never take economic parameters95 from caller choice. Derive them from accepted stored policy, derived state, a sealed96 adapter type, or a compiled value that is itself the accepted immutable97 policy. Otherwise fail closed.9899## If the contract verifies off-chain signatures100101- Bind authorization to the exact action, actor or beneficiary, target object or original type, expiry, and any domain not already fixed by a dedicated key.102- Reject malformed or non-canonical messages before verification. Prevent replay, and make third-party submission fail harmlessly or produce only the approved effect.103- If one key spans actions, deployments, or networks, use explicit domain separation and document the shared compromise scope.104105## Prevent replay with linearity106107- Prefer consuming a unique authorization resource over storing `claimed: bool` or a parallel nonce.108- Validate first, consume the resource, construct the result, emit the final-state event, then return the result.109- Use non-copyable, non-droppable payloads for migration, flash, or settlement handoffs.110- Require the exact sealed witness type to redeem a cross-package handoff.111- When admitting a witness by `TypeName`, reject primitive and vector types and prove its constructor is sealed in the approved module; `TypeName` alone cannot prove construction rights.112- Treat events as index facts, never replay guards.113- For a repeatable signed operation, consume a nonce, digest, or linear authorization exactly once and define bounded storage, eviction, and cleanup. Permit intentional replay only when it is documented and safe.114115## Bound state and work116117- Bound every persistent collection with a named protocol constant, and record the reachable maximum plus intentional slack.118- Bound every loop whose input can grow on chain.119- Check duplicates before consuming capacity.120- Define behavior at capacity. When bounded work is optional, prefer a safe liveness-preserving fallback over aborting the user's primary transition.121- Test empty, full, first-over-capacity, duplicate, removal, and re-addition cases.122- Avoid public inputs that cause unbounded deserialization, iteration, event size, or dynamic-field growth.123- Keep pending work and retry state bounded and explicitly releasable.124125## Load external-input guidance when applicable126127For deadlines, time-dependent authorization, slippage, oracles, price feeds, or128random outcomes, read129[Time, oracles, and randomness](references/time-oracles-randomness.md)130completely before designing, changing, or reviewing the transition.131132## Load DeFi guidance when applicable133134For shares, vaults, liquid staking, farms, rewards, AMMs, lending,135liquidations, or other DeFi accounting, read136[DeFi security](references/defi-security.md) completely before designing,137changing, or reviewing the transition. Apply it with this skill's invariant,138fail-fast, custody, oracle, and external-seam rules.139140## Preserve conservation and custody141142Write and test one operation-specific identity per asset type, never a mixed-unit equation, derived from:143144```text145assets in = assets out + reserves + accrued fees + pending custody + explicitly burned amount146```147148- Keep reserves, fees, pending burns, allocations, residuals, and claims separate when their owner or terminal treatment differs.149- For every admitted asset, document its original type, mint and supply150 authority, deny, pause, or action restrictions, units, and authoritative151 balance delta.152- Reject an asset whose controls can break mandatory settlement or exit153 invariants unless an accepted admission decision records and bounds that risk154 explicitly.155- Use actual balances as authority, never event-only counters or SDK previews.156- Reconcile after every operation and multi-operation sequence.157- Make burn, disposal, refund, fee, residual, and rounding treatment explicit.158- Do not call disposal a burn unless native supply authority confirms destruction.159- Reject unexpected residuals or clamps that could conceal a broken invariant.160161## Defend external seams162163- Perform every locally available check before external reads, calls, or asset handoffs.164- Validate returned object identity, original type, package, pair, tier, units, amounts, actual balance deltas, liquidity, price deviation, freshness, and residual bounds.165- Keep external dependency and failure surfaces in adapters, not core.166- Do not cargo-cult an EVM reentrancy guard onto ordinary statically resolved Move calls. Threat-model PTB composition and flash, hot-potato, or explicit callback-like handoffs; lock only the smallest shared seam until exact receipt and repayment validation completes.167- Do not support an external venue whose required payment or custody model violates core invariants.168- Verify deployed bytecode and ABI; a local link stub proves type compatibility only.169170## Define pause behavior171172- Define pause scope exactly and preserve user exits and mandatory settlement173 unless the design explicitly rejects them.174- Let emergency authority reduce risk, not seize, reprice, or rewrite user175 accounting.176177## Load upgrade guidance when applicable178179Before changing or reviewing publication, upgrades, package-capability custody,180operational versioning, shared-state migration, or dependency relinking, read181[Upgrade security](references/upgrade-security.md) completely. Also read it182when old and new package versions can both reach shared protocol state changed183by the task.184185## Protect sensitive material186187- Keep secrets, private transaction material, and deployment credentials out188 of source, logs, fixtures, and summaries.