Sui.

Post

Share your knowledge.

SuiLover.
Jul 30, 2025
Expert Q&A

How can I unauthorized upgrades of a Move package?

I'm trying to understand this aspect of the Sui Network because I'm either building, debugging, or deploying something that touches this area. I want a detailed explanation of how this mechanism or feature works, along with relevant CLI usage, Move code structure, or architectural concepts. My goal is to gain enough clarity to apply this knowledge in a real project—whether that's a custom smart contract, an NFT system, a wallet integration, or a DeFi tool. The Sui Network has unique features compared to EVM chains, so I'm particularly interested in what sets it apart and how that affects development best practices. It would help to have sample code, command line examples, or typical errors to watch for, especially when using the Sui CLI, SDK, or deploying on localnet/testnet. Ultimately, I want to avoid common mistakes, follow the best security principles, and ensure that the functionality I’m working on behaves as expected under realistic conditions.

  • Sui
  • Transaction Processing
  • Move
4
14
Share
Comments
.

Answers

14
BigSneh.
Jul 30 2025, 12:28

To prevent unauthorized upgrades of a Move package on Sui, the key mechanism is the upgrade_cap object. This object acts as an on-chain capability that grants exclusive authority to upgrade a deployed package. Without possession of the upgrade_cap, no one can upgrade the package, thus securing it against unauthorized changes.

When you publish a package using the Sui CLI:

sui client publish --path ./my_package --gas-budget 10000

The system creates an upgrade_cap object and returns its object ID. This object must be included in any upgrade transaction, like so:

sui client upgrade --package ./new_package --upgrade-cap <upgrade_cap_object_id> --gas-budget 10000

To secure your package:

  1. Safeguard the upgrade_cap: Store it securely in a hardware wallet or multisig wallet to ensure only authorized entities can sign upgrade transactions.

  2. Use multisig wallets for upgrade authority: Wrap the upgrade_cap inside a multisig wallet object. This requires multiple signatures before the upgrade transaction is accepted, adding a layer of security.

  3. Implement off-chain governance controls: Coordinate upgrades with off-chain approval processes to avoid rogue upgrades.

  4. Do not share the upgrade_cap with unauthorized parties or expose it in insecure environments.

  5. Use environment-specific access controls: For example, restrict upgrade operations to specific deployment environments or IP whitelists in your operational infrastructure.

  6. Audit upgrade transactions: Monitor the blockchain for any unauthorized or unexpected upgrade calls to react promptly.

If you lose control of the upgrade_cap, your package can be upgraded by anyone holding it, which compromises your contract’s integrity. Conversely, if you lose the upgrade_cap entirely and don’t have a backup, you cannot upgrade the package anymore, effectively freezing its state.

Unlike Ethereum’s proxy upgrade patterns where upgradeability is encoded in contract logic, Sui uses an explicit capability object. This design enhances security transparency by tying upgrade authority directly to an on-chain object that you control.

In your Move code, the upgrade_cap does not appear because upgrade permissions are managed outside contract logic, but it is critical in deployment and upgrade transactions via CLI or SDK.

Example to check your package’s upgrade capability:

sui client get-package <package_id>

This will show package metadata including the upgrade_cap object.

By following these practices, you ensure that package upgrades are strictly controlled, mitigating risks of unauthorized changes and maintaining user trust in your smart contracts.

7
Best Answer
Comments
.
Ashford.
Jul 31 2025, 06:35

Unauthorized Upgrades in Sui Network (Move)

To prevent unauthorized upgrades of a Move package in the Sui Network, you need to ensure that only trusted entities or addresses are allowed to perform upgrades. This is done through the upgrade_cap mechanism and by carefully controlling who has the ability to upgrade your package.

Key Concepts:

  • upgrade_cap: A capability that restricts who can upgrade a package. You can set and check the upgrade_cap during contract deployment.
  • Contract Upgrade Process: Sui contracts, once deployed, can be upgraded, but you need to control who can trigger these upgrades.

Steps to Prevent Unauthorized Upgrades:

  1. Set upgrade_cap: When deploying your Move package, define the upgrade_cap to restrict who can upgrade your contract.
  2. Grant Upgrade Permissions: Only provide the upgrade capability to trusted addresses (e.g., admins).

Example Move Code:

module MyPackage {
    use 0x1::UpgradeCap;

    public fun initialize(owner: address) {
        let cap = UpgradeCap::new(owner);  // Create upgrade capability for the owner
        // Store the upgrade cap in a resource or object
    }

    public fun upgrade(owner: address) {
        // Only the owner (who has the upgrade cap) can call this function
        UpgradeCap::assert_cap(&cap, owner); // Ensure the caller has the upgrade cap
        // Perform the upgrade logic here
    }
}

CLI Example for Setting Up upgrade_cap:

When publishing or deploying a Move package, you can pass the upgrade_cap identifier to the Sui client:

sui client publish --gas-budget 10000 --upgrade-cap <upgrade-cap-id>

Common Mistakes:

  • Not properly associating the upgrade_cap: If the upgrade capability isn't correctly set, unauthorized addresses may accidentally gain permission to upgrade the contract.
  • Wrong address for upgrade: Ensure that only authorized addresses (the ones holding the upgrade_cap) are able to perform the upgrade.

Best Practices:

  • Limit Upgrade Capability: Only give the upgrade_cap to trusted addresses or admins.
  • Test on Testnet/Localnet: Always test your upgrade logic on local/test networks to ensure that unauthorized upgrades are prevented.
  • Securely Store the upgrade_cap: Make sure the address holding the upgrade capability is securely managed.

By controlling the upgrade_cap and carefully limiting who can trigger upgrades, you can avoid unauthorized upgrades and ensure that your contract remains secure after deployment.

7
Comments
.
Benjamin XDV.
Jul 31 2025, 09:44

To unauthorize upgrades of a Move package in Sui, you must revoke or burn the upgrade_cap object, as this capability is the sole mechanism for authorizing package upgrades. Once the upgrade_cap is destroyed (e.g., via public entry fun burn in Move), the package becomes immutable permanently, as Sui enforces strict upgradeability control at the protocol level. This differs from EVM chains where upgradability relies on proxy patterns or mutable storage—Sui’s model ensures deterministic security by tying upgrades explicitly to capability ownership. Best practice is to implement a governance-controlled wrapper (e.g., AdminCap) around the upgrade_cap for programmable revocation, rather than burning it directly, to allow for future decentralization.

6
Comments
.
theking.
Jul 30 2025, 11:25

To unauthorized or disable upgrades for a Move package on the Sui Network, you need to destroy or transfer the UpgradeCap object that was generated during the initial deployment of the package. The UpgradeCap is a special object that grants permission to upgrade that specific package. Without this capability, no future upgrades are possible.

To prevent upgrades, you can transfer the UpgradeCap to an inaccessible address (like 0x0) or destroy it using a Move function you control. For instance, if you want to make the contract immutable, include a public entry fun burn_upgrade_cap(cap: UpgradeCap) function in your module and simply call it after deployment. Once burned, upgrades are permanently disabled.

Here’s a sample Move snippet for burning:

public entry fun burn_upgrade_cap(cap: UpgradeCap) {
    sui::package::delete_upgrade_cap(cap);
}

If you’re deploying via CLI, you can call this entry function after publishing:

sui client call \
  --package <your_package_id> \
  --module <your_module> \
  --function burn_upgrade_cap \
  --args <upgrade_cap_object_id>

Disabling upgrades is essential when you want to lock your smart contract logic permanently for security or governance reasons. Once the cap is destroyed or moved to an address with no private key, the package is fully immutable.

5
Comments
.
Paul.
Paul4310
Jul 31 2025, 05:36

To prevent unauthorized upgrades of a Move package in Sui, you can implement access control for the upgrade process. Specifically, you can use the upgrade_cap (upgrade capability) and ensure it is securely controlled by a trusted entity or account.

Key Concepts:

  • Upgrade Capabilities: Control who can upgrade the Move package by associating the upgrade_cap with a trusted address.
  • Access Control: Only allow the account that holds the upgrade capability to trigger an upgrade.

Best Practices:

  1. Secure upgrade_cap Ownership: Only give upgrade rights to trusted addresses (e.g., the deployer account).
  2. Use Signatures: Implement logic to verify the signer during the upgrade process to ensure only authorized users can execute the upgrade.

Example Code:

module MyModule {
    use sui::object::{Object, upgrade_cap};

    public fun upgrade(beneficiary: &signer) {
        let cap = upgrade_cap::get_cap(beneficiary);
        assert!(cap.is_some(), 0); // Ensure the signer is authorized
        // Logic for upgrading the contract
    }
}

CLI Usage:

Use the Sui CLI to publish and manage upgrades securely:

sui client publish --upgrade --package <package-id> --capability <upgrade-cap-id>

Common Mistakes to Avoid:

  • Loose Access Control: Avoid assigning upgrade_cap to non-trusted accounts.
  • State Incompatibility: Ensure the upgrade does not break existing object states or data structures. Always test on localnet/testnet first.
5
Comments
.
Arnold.
Arnold3036
Jul 31 2025, 08:18

To prevent unauthorized upgrades of a Move package:

1. Make the Package Immutable

// During publishing, set `UpgradePolicy` to `immutable`  
let upgrade_cap = package::claim_and_keep(otw);  
package::make_immutable(upgrade_cap);  // 🔐 Burn upgrade capability  
  • Effect: No further upgrades allowed (like EVM contracts).

2. Securely Manage UpgradeCap

If upgrades are needed:

  • Transfer upgrade_cap to a multisig/DAO:
    transfer::transfer(upgrade_cap, @multisig_address);  
    
  • Use custom auth logic:
    public entry fun upgrade(  
      _: &AdminCap,  // Requires admin permission  
      upgrade_cap: &mut UpgradeCap,  
      new_package: vector<u8>  
    ) { package::upgrade(upgrade_cap, new_package); }  
    

CLI Example (Publish Immutable)

sui client publish --gas-budget 100000000  
# Then call `make_immutable` with the returned `upgrade_cap` ID  

Key Differences from EVM

  • Sui: Upgradeability is opt-in (via UpgradeCap).
  • EVM: Contracts are immutable by default (no native upgrade mechanism).

Common Pitfalls

  1. Losing upgrade_cap: Transfers to a dead address = irreversible.
  2. Overprivileged Upgrades: Avoid granting upgrade rights to EOAs.
4
Comments
.
shamueely.
Jul 30 2025, 11:31

To make sure no one can upgrade a Move package on the Sui network—including yourself—you need to revoke the authority tied to the package’s UpgradeCap object. This is the object that controls permission for future upgrades. If you delete or make this object inaccessible, the package becomes immutable and can never be modified again.

You can do this securely using the sui::package::delete_upgrade_cap function in your Move code. Here’s a simple example you can add to your module:

use sui::package;
use sui::package::UpgradeCap;

public entry fun lock_package(cap: UpgradeCap) {
    package::delete_upgrade_cap(cap);
}

Then, once you deploy the package, execute this function in a transaction using the Sui CLI or SDK:

sui client call \
  --package <your_package_id> \
  --module <your_module_name> \
  --function lock_package \
  --args <upgrade_cap_object_id> \
  --gas-budget 100000000

By doing this, the UpgradeCap is burned, which means it no longer exists on-chain, and no one can authorize another upgrade. This is a best practice if you want to ensure code immutability—especially for production-ready DeFi contracts, NFT standards, or any logic where users rely on trustless, locked behavior.

For architectural context: unlike EVM where smart contracts are immutable by default, Sui allows upgradeable packages, which gives flexibility but also introduces governance complexity. To “unauthorize” upgrades, you must explicitly destroy the key that allows them.

Read more in the official Sui package upgrade documentation here: https://docs.sui.io/build/packages-and-upgrades#making-packages-immutable

3
Comments
.
Alya.
Alya-14
Jul 30 2025, 17:29

To prevent unauthorized upgrades of a Move package in Sui, destroy or lock the upgrade_cap object after publication.

The upgrade_cap (from 0x2::package::UpgradeCap) is a first-class object that grants upgrade authority. If it remains in the publisher’s address, anyone with access can upgrade the package.

Best Practices:

  • For immutable contracts: Burn the capability:
    public entry fun burn_upgrade_cap(cap: package::UpgradeCap) {
        package::discard(cap); // Destroys the capability
    }
    
  • For governed upgrades: Transfer upgrade_cap to a multisig or DAO module instead of keeping it in a single account.
  • Never expose upgrade_cap in public functions without access control.

CLI Check:

sui client object --id [PACKAGE_ID]  # Look for associated UpgradeCap object

Once the upgrade_cap is destroyed, the package becomes permanently immutable—this is Sui’s equivalent of "locking" a contract (like EVM's upgradeability patterns).

This mechanism is unique to Sui’s object-centric model: upgrade permission is enforced by object ownership, not by admin roles or logic within the contract.

3
Comments
.
Evgeniy CRYPTOCOIN.
Jul 31 2025, 09:12

To prevent unauthorized upgrades in Sui:

  1. Burn the UpgradeCap – Destroy it after deployment for immutability.
  2. Lock in init – Don’t share the cap if permanent immutability is needed.

Move Example:

public fun lock_forever(cap: UpgradeCap) {  
    sui::package::make_immutable(cap) // Burns cap  
}  

Key Notes:
✔ Without UpgradeCap, no upgrades are possible.
✔ Unlike EVM, Sui allows reversible immutability.

CLI Alternative:

sui client call --function lock_forever --args <CAP_ID>  

(Warning: Permanent unless you pre-plan recovery methods.)

3
Comments
.
290697tz.
Jul 30 2025, 12:30

To prevent unauthorized upgrades of a Move package on Sui, the core mechanism is the upgrade_cap object. This capability object grants exclusive authority to upgrade a deployed package. Without possessing the upgrade_cap, no one can upgrade the package, ensuring security.

When you publish a package via Sui CLI:

sui client publish --path ./my_package --gas-budget 10000

An upgrade_cap object is created and returned. This object ID must be provided when upgrading the package:

sui client upgrade --package ./new_package --upgrade-cap <upgrade_cap_object_id> --gas-budget 10000

To secure the upgrade process:

  1. Store the upgrade_cap securely, such as in a hardware wallet or multisig wallet.

  2. Use a multisig wallet to hold the upgrade_cap so multiple signatures are required for upgrades.

  3. Avoid sharing the upgrade_cap object ID or exposing it publicly.

  4. Implement off-chain governance to approve upgrades before execution.

  5. Restrict upgrade access with environment controls or infrastructure whitelisting.

  6. Monitor blockchain transactions to detect unauthorized upgrade attempts.

  7. Back up the upgrade_cap securely to avoid losing upgrade ability.

  8. Remember that losing the upgrade_cap means you cannot upgrade your package anymore.

  9. Unlike EVM proxies, Sui’s upgrade control is managed by a distinct object, not contract logic.

  10. The Move code itself does not hold upgrade logic; it's handled externally via the upgrade_cap.

  11. The upgrade_cap is tied to the package’s metadata and visible when querying package info:

sui client get-package <package_id>

  1. Always verify the upgrade_cap ownership before attempting upgrades.

  2. When upgrading, the package ID remains constant; only the code changes.

  3. Unauthorized possession of the upgrade_cap allows malicious upgrades.

  4. Use access control mechanisms in your operational environment to protect upgrade transactions.

  5. Design your CI/CD pipeline to require manual approval steps for upgrades.

  6. Track who holds the upgrade_cap in your team or organization for accountability.

  7. You can transfer the upgrade_cap object to another account if needed, but do so cautiously.

  8. Keep upgrade transactions gas-efficient by specifying appropriate gas budgets.

  9. Combining on-chain upgrade_cap control with off-chain governance is the best practice for secure package upgrades on Sui.

2
Comments
.
Jeff.
Jeff2046
Aug 23 2025, 08:54

To prevent unauthorized upgrades of a Move package on Sui, the core mechanism is the upgrade_cap object. This capability object grants exclusive authority to upgrade a deployed package. Without possessing the upgrade_cap, no one can upgrade the package, ensuring security.

When you publish a package via Sui CLI:

sui client publish --path ./my_package --gas-budget 10000

An upgrade_cap object is created and returned. This object ID must be provided when upgrading the package:

sui client upgrade --package ./new_package --upgrade-cap <upgrade_cap_object_id> --gas-budget 10000

To secure the upgrade process:

Store the upgrade_cap securely, such as in a hardware wallet or multisig wallet.

Use a multisig wallet to hold the upgrade_cap so multiple signatures are required for upgrades.

Avoid sharing the upgrade_cap object ID or exposing it publicly.

Implement off-chain governance to approve upgrades before execution.

Restrict upgrade access with environment controls or infrastructure whitelisting.

Monitor blockchain transactions to detect unauthorized upgrade attempts.

Back up the upgrade_cap securely to avoid losing upgrade ability.

Remember that losing the upgrade_cap means you cannot upgrade your package anymore.

Unlike EVM proxies, Sui’s upgrade control is managed by a distinct object, not contract logic.

The Move code itself does not hold upgrade logic; it's handled externally via the upgrade_cap.

The upgrade_cap is tied to the package’s metadata and visible when querying package info:

sui client get-package <package_id>

Always verify the upgrade_cap ownership before attempting upgrades.

When upgrading, the package ID remains constant; only the code changes.

Unauthorized possession of the upgrade_cap allows malicious upgrades.

Use access control mechanisms in your operational environment to protect upgrade transactions.

Design your CI/CD pipeline to require manual approval steps for upgrades.

Track who holds the upgrade_cap in your team or organization for accountability.

You can transfer the upgrade_cap object to another account if needed, but do so cautiously.

Keep upgrade transactions gas-efficient by specifying appropriate gas budgets.

Combining on-chain upgrade_cap control with off-chain governance is the best practice for secure package upgrades on Sui.

2
Comments
.
Bekky.
Bekky1762
Jul 31 2025, 10:29

1. Core Security Mechanism

Sui uses upgrade caps (UpgradeCap) to control package mutability. Unlike EVM's immutable contracts, Sui allows upgrades but with strict ownership controls.

Key Properties

FeatureDescription
UpgradeCapTransferable object granting upgrade rights
PoliciesBitflags defining allowed changes (backwards-compatible, additive, breaking)
Digest VerificationEnsures bytecode matches expected hash

2. Implementation Patterns

Basic Immutable Package

module my_pkg::governance {
    use sui::package;
    use sui::transfer;
    use sui::tx_context;

    // Burn upgrade cap at initialization
    public fun init(ctx: &mut TxContext) {
        let (upgrade_cap, _) = package::claim_upgrade_cap(ctx);
        package::burn_upgrade_cap(upgrade_cap); // Permanent immutability
    }
}

DAO-Controlled Upgrades

module my_pkg::dao {
    use sui::voting;
    use sui::package;

    struct DaoCap has key, store {
        id: UID,
        upgrade_cap: UpgradeCap,
        threshold: u64
    }

    public entry fun authorize_upgrade(
        dao: &mut DaoCap,
        proposal_id: ID,
        policy: u8,
        digest: vector<u8>,
        ctx: &mut TxContext
    ) {
        assert!(voting::is_approved(proposal_id, dao.threshold), EACCESS_DENIED);
        package::authorize_upgrade(&mut dao.upgrade_cap, policy, digest);
    }
}

3. CLI Enforcement

Deploy as Immutable

sui client publish --gas-budget 1000000000 --with-upgrade-capability false

Verify Immutability

sui client object <UPGRADE_CAP_ID> --json | grep "burned"
# Expected: "burned": true

4. Security Best Practices

Upgrade Policy Matrix

Policy FlagAllowed ChangesRecommended For
0x1 (COMPATIBLE)Bug fixes onlyStable protocols
0x3 (ADDITIVE)New functionsEvolving systems
0x7 (BREAKING)Full changesEarly development

Multi-Sig Protection

module my_pkg::multisig {
    struct UpgradeVault has key {
        id: UID,
        cap: UpgradeCap,
        required: u8,
        approvals: vector<address>
    }

    public entry fun approve(
        vault: &mut UpgradeVault,
        signer: &signer
    ) {
        let addr = signer::address_of(signer);
        assert!(!vector::contains(&vault.approvals, &addr), EALREADY_APPROVED);
        vector::push_back(&mut vault.approvals, addr);
        
        if (vector::length(&vault.approvals) >= vault.required) {
            package::authorize_upgrade(&mut vault.cap, POLICY_ADDITIVE, digest);
        }
    }
}

5. Attack Vectors & Mitigations

ThreatSolutionMove Example
Stolen CapTime-lock upgradesstruct TimedCap { unlock_epoch: u64 }
Malicious UpgradeRequire digest verificationassert!(digest == expected_digest, EINVALID)
Governance TakeoverProgressive decentralizationStart with required = 5/7 multisig

6. Testing Strategies

Localnet Dry-Run

sui client publish --upgrade-policy 1 --dry-run
# Verify no upgrade cap is created

Negative Test Case

#[test(expected_failure = "EUPGRADE_NOT_AUTHORIZED")]
fun test_unauthorized_upgrade() {
    let (_, publisher) = package::claim_upgrade_cap(ctx);
    package::authorize_upgrade(&mut cap, 0x7, digest); // Should fail
}

7. Monitoring & Recovery

On-Chain Verification

// TypeScript SDK check
const isImmutable = await client.getObject({
    id: upgradeCapId,
    options: { showContent: true }
}).then(obj => obj.data?.content?.type === '0x2::package::UpgradeCap');

Emergency Freeze

public entry fun freeze_forever(cap: UpgradeCap) {
    transfer::freeze_object(cap); // Makes cap non-transferable
}

Key Differentiators from EVM

AspectSuiEVM
Upgrade MechanismObject-centricProxy patterns
GranularityPer-package controlAll-or-nothing
AuditabilityOn-chain upgrade historyOpaque proxy admins

For production systems:

  1. Store UpgradeCap in cold storage
  2. Implement multi-sig with time delays
  3. Use Sui Explorer to monitor upgrade proposals
1
Comments
.

Do you know the answer?

Please log in and share it.

Sui is a Layer 1 protocol blockchain designed as the first internet-scale programmable blockchain platform.

1170Posts3665Answers
Sui.X.Peera.

Earn Your Share of 1000 Sui

Gain Reputation Points & Get Rewards for Helping the Sui Community Grow.

Reward CampaignAugust