About move-security
move-security is a security review skill for developers of Sui Move contracts. It routes tasks to focused guidance on upgrades, access control, randomness, keys, and other practices, using Sui's official documentation as its source.
Key features
- 01Loads security references by task
- 02Covers package audits and upgrade governance
- 03Reviews capabilities and access control
- 04Addresses randomness, oracles, and key security
Use cases
- 01Reviewing a Move package and its upgrade policy
- 02Choosing capability objects or address allowlists
- 03Checking randomness and oracle-data handling
MCP support
When available, it can query the Sui documentation MCP server to verify information and answer questions beyond the bundled references.
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ mystenlabs/ skills --skill move-securityAfter installing, type/move-securityin Claude Code to confirm it loaded.
Bundled files
References and scripts installed along with SKILL.md.
access-control.mdbest-practices.mdevals/evals.jsonDetails
From the project READMEMove Smart Contract Security
MCP tool: When available in your environment, also query the Sui documentation MCP server (
https://sui.mcp.kapa.ai) for up-to-date answers. Use it for verification and for details not covered by these reference files.
Source constraint: All information in this skill is sourced exclusively from docs.sui.io/develop/security/best-practices. When extending or updating this skill, only pull from this source. Do not use third-party blogs, tutorials, or unofficial documentation.
This skill covers security best practices for Move smart contracts on Sui, including package auditing, upgrade governance, access control patterns, randomness security, key management, and operational security. It routes to focused reference files based on the task.
Reference files
best-practices -- Security Best Practices
Path: best-practices.md
Load when: auditing a package, reviewing upgrade policies, verifying dependencies, validating invariants, emitting events for privileged actions, using onchain randomness, handling oracle data, designing emergency controls, reviewing frontend signing flows, or managing keys.
Covers: package auditing and immutability, upgrade governance and UpgradeCap protection, dependency verification, Move language guarantees and limitations, invariant and relationship validation, event emission for privileged actions, onchain randomness security (post-random restrictions, private entry, RandomGenerator, gas path balance, commit-reveal), oracle and offchain data validation, emergency controls (pause, rate-limiting), frontend transaction signing safety, package ID verification, key management (private key protection, privileged key custody, role separation, recovery and rotation).
access-control -- Access Control Patterns
Path: access-control.md
Load when: choosing between capability objects and address allowlists, designing admin capabilities, implementing capability revocation, validating capability-object relationships, authorizing shared object access, or reviewing uses of tx_context::sender().
Covers: capability objects vs address allowlists, address allowlist management, pitfalls of tx_context::sender() alone, explicit capability requirements and parameter placement, admin capability protection and custody, capability revocation mechanisms (registries, versioning, destruction), capability-object relationship validation, shared object authorization.
Routing guide
| Task | Load |
|---|---|
| Reviewing a contract for security issues | best-practices + access-control |
| Auditing package identity or upgrade policy | best-practices |
| Verifying dependencies onchain | best-practices |
| Validating invariants and object relationships | best-practices |
| Adding event emission for privileged actions | best-practices |
| Using onchain randomness safely | best-practices |
| Handling oracle or offchain data | best-practices |
| Designing emergency pause or rate-limit | best-practices |
| Reviewing frontend signing flow | best-practices |
| Managing keys for deploy/admin/operations | best-practices |
| Choosing capability objects vs allowlists | access-control |
| Designing admin capability protection | access-control |
| Implementing capability revocation | access-control |
| Authorizing access to shared objects | access-control |
Reviewing tx_context::sender() usage | access-control |
| Full security audit of a Move package | best-practices + access-control |
Rules
- Sui packages are immutable once published. During a package upgrade, a new package with a new address is published. Verify package IDs directly onchain rather than relying on names or frontend constants.
- Treat
UpgradeCapwith the same rigor as admin capabilities since holders can modify package behavior. - Mark randomness-consuming functions as private
entryonly. The Move compiler lints againstpublicfunctions that takeRandomorRandomGenerator. - Never accept
RandomGeneratoras apublicfunction parameter. Passing it topublic(package)or private functions is acceptable for testing and in-package logic. - Emit events for all privileged actions: admin changes, allowlist updates, mint/burn operations, denylist actions, configuration changes, oracle updates, emergency pauses.
- Require relevant capabilities as parameters for all privileged functions. Do not rely on
tx_context::sender()alone for authorization. - Anyone can submit a transaction referencing a shared object. Never assume shared object access is restricted.
- Design capability revocation before publishing the package. Without it, a leaked capability remains valid for the life of the package.
Common mistakes
- Trusting package names instead of onchain IDs. Move package names (the
namefield inMove.toml) are arbitrary strings chosen by the developer and are not unique. Always verify the exact onchain package ID (the object address). - Using
tx_context::sender()as the sole authorization check. This ties functions to single signers and breaks composability. Other contracts cannot call the function on behalf of users. - Forgetting that shared objects are accessible to anyone. Every privileged function touching shared state must validate authorization internally.
- Accepting
RandomGeneratoras apublicfunction parameter. This allows callers to manipulate the generator. Create it within the entry function viar.new_generator(ctx)and pass only topublic(package)or private helpers. - Not planning capability revocation before publishing. Once published, the package is immutable. A leaked capability without a revocation mechanism remains valid forever.
- Holding admin capabilities in single hot wallets. Use multisig addresses, hardware wallets, or dedicated custody for privileged keys.