Introduction
On December 1st, 2025, Aleo Foundation tasked zkSecurity with auditing their Multisig Wallet program and its integration into several applications and protocols. The specific code to review was shared via both public and private GitHub repositories. The audit lasted one week with two consultants.
Scope
The main purpose of multisig wallet currently boils down to two use cases:
- Requiring multiple signatures for program upgrades.
- Requiring multiple signatures for admin-specific functions of several different applications and protocols.
For this reason, this audit not only focused on the multisig core engine, multisig_core, but also covered how this engine is utilized by other applications and protocols to gate upgrades (e.g., in test_upgrade) and admin functions (e.g., in Hyperlane’s warp tokens).
More specifically, we reviewed the following programs:
Repo: https://github.com/AleoNet/aleo-multisig
- The
multisig_coreprogram, which is the core multisignature engine, at commit940050959f5877ba59f2889430f5b0e7a6a6e96f. - The
test_upgradesprogram, which shows how program upgrades can be gated behind a multisig operation, at commit940050959f5877ba59f2889430f5b0e7a6a6e96f.
Repo: https://github.com/eranrund/hyperlane-aleo/tree/eran/multisig
- The
hyp_multisigprogram, which can be used to gate privileged operations on Hyperlane’smailbox,ism_manager, andhook_managerprograms, at commita978035035900d72ea68073ccb23cda73bf5a68f. - The
hyp_warp_multisigprogram, which represents the interface program betweenmultisig_coreand Hyperlane’s warp token programs, at commita978035035900d72ea68073ccb23cda73bf5a68f.
Repo: https://github.com/sealance-io/compliant-transfer-aleo
- The
compliant_token_templateprogram, which provides a token template that includes freeze list enforcement, at commit052bbd9d26336ac3f9cefae2c9595df7c26bcaaf. - The
sealance_freezelist_registryprogram, which is the freeze list registry used by thecompliant_token_template, at commit052bbd9d26336ac3f9cefae2c9595df7c26bcaaf.
Repo: private
- The
circle_bridgeprogram, which handles cross-chain token transfers between Ethereum and Aleo, at commit45e0aa94d6041cd0874c0c73eec697c53decc8ed.
Scope Variance
This section outlines several changes present in the deployed commit that were not included in the original audit scope, while noting that the deployed version continues to use multisig program upgrades covered in the audit.
More specifically, the differences are as follows:
- The same
multisig_coreprogram, which differs only by the removal of theUPGRADER_ADDRESSconstant. Instead, theUPGRADER_ADDRESSis stored in a mapping and is initialized as part of theinit()transition. It can later be updated via theset_upgrader_address()transition (until upgrades are disabled bydisallow_upgrades()). - The
stablecoin_program, which is equivalent to the auditedcompliant_token_template, but differs by removing multisig administrative actions (not to be confused with multisig-controlled program upgrades, which remain intact), and removing multisig version of mint and burn. - The
freezelist_program, which is equivalent to the auditedsealance_freezelist_registry, which differs only by the removal of multisig administrative actions. - The same
circle_bridgeprogram, which incorporates the same difference as above: removal of multisig administrative actions.
Although these variants were not part of the original audit scope, they rely on the same multisig upgrade flow and structural assumptions evaluated in the audited codebase.
For completeness in the report, we also reference the corresponding commits in the Provable compliant-stablecoin repository (https://github.com/ProvableHQ/compliant-stablecoin) at commit d3dda6117c47d043f12b448e6c8f912f519bddb1 and note that these versions have been reviewed at a high level as part of this variance assessment.
Overview
Multisig core
multisig_core.aleo implements a reusable t-of-n threshold multi-signature engine for Aleo programs. It manages wallets (identified by Aleo addresses), tracks authorized signers (both Aleo signature and ECDSA), enforces signature thresholds for arbitrary operations, and exposes admin transitions to adjust signer sets or thresholds. State lives in the following mappings:
wallets_map: stores each wallet’s threshold and signer countsigners_map: tracks hashed signer identitiespending_signing_ops: tracks signing roundscompleted_signing_ops: tracks completion status
Program Flow
- Wallet setup: Use
create_walletto register a wallet ID, threshold, and signer set. This populateswallets_mapand hashes each signer intosigners_map. - Operation initiation: A participant calls
initiate_signing_opfrom their Aleo account. The transition hashes(wallet_id, signing_op_id)intowallet_signing_op_id_hash, ensures no active/completed round exists, creates a newpending_signing_opstruct, and, if the caller is a registered signer, records their signature as the first confirmation. - Collect signatures: Each authorized signer calls
sign(for Aleo signature) orsign_ecdsa(for ECDSA) with the samewallet_idandsigning_op_id. The contract confirms the signer is registered, the pending op exists and hasn’t expired, the round value matches (if specified), and the signer hasn’t already signed this round. It increments confirmations, and once the count meets the current threshold, records the op incompleted_signing_ops. - Execution in consuming program: Program can then call
assert_signing_completed(wallet_id, signing_op_id)which checks ifwallet_signing_op_id_hashexist in thecompleted_signing_ops, before performing any sensitive action. This ensures that the specific action (bound to thesigning_op_id) is gated by the multisignature approval before proceeding.
In addition to the basic flow, the program also handles administrative actions for updating wallet policy — such as adding or removing signers and increasing or decreasing the signing threshold — following the same flow as normal wallet-signing operations. This ensures that governance updates are subject to the same multisig protections as any other action.
Note that during wallet setup, the program also supports a Guarded wallet configuration, where any call to create_wallet must be pre-approved by the “guard wallet,” which is simply the multisig_core.aleo program’s own address used as the wallet_id. This special wallet can only be created by the program deployer when the Guarded wallet setting is enabled.
Multisig Program Upgrades
The multisig functionality can be used to gate program upgrades behind multisignature approvals.
It is demonstrated in the test_upgrades example below:
program test_upgrades.aleo {
struct ChecksumEdition {
checksum: [u8; 32],
edition: u16,
}
// A helper for calculating a signing_op_id from the program's checksum and edition.
// By deriving the signing_op_id from both we ensure that downgrades cannot take place.
transition get_signing_op_id_for_deploy(checksum: [u8; 32], edition: u16) -> field {
return BHP256::hash_to_field(ChecksumEdition { checksum: checksum, edition: edition });
}
@custom
async constructor() {
// Only require multisig for upgrades - initial deployment has no checks.
if self.edition > 0u16 {
let signing_op_id = BHP256::hash_to_field(ChecksumEdition { checksum: self.checksum, edition: self.edition });
let wallet_signing_op_id_hash = BHP256::hash_to_field(WalletSigningOpId { wallet_id: self.address, signing_op_id: signing_op_id });
let signing_complete = multisig_core.aleo/completed_signing_ops.contains(wallet_signing_op_id_hash);
assert(signing_complete);
}
}
transition main(public a: u32, b: u32) -> u32 {
let c: u32 = a + b;
return c;
}
}
Before deploying a new program edition, maintainers derive a signing_op_id from the target edition and the bytecode checksum, and then run a multisig round using a wallet_id equal to the program’s address.
Once enough signatures have accumulated, the constructor of the upgraded program checks completed_signing_ops for the corresponding wallet_signing_op_id_hash, which binds together the program address, program edition, and its checksum. If the signing operation has not been approved, the constructor rejects the deployment.
Hyperlane Multisig
The Hyperlane Protocol
Hyperlane is a permissionless cross-chain messaging protocol that enables applications to send arbitrary messages between blockchains.
Conceptually, the protocol has two main flows:
- The Dispatch Flow (on the origin chain)
An application calls
dispatchto initiate the sending of a message from the origin chain to the destination chain. - The Process Flow (on the destination chain)
An off-chain relayer collects that message and calls
processto submit the message on the destination chain, where it is verified and then executed by a target application.
The Hyperlane protocol has three main actors: applications, validators, and relayers. Applications are the “users” of the protocol. They are the ones initiating and receiving cross-chain messages. On the origin chain, an application’s entry point for sending a message is Hyperlane’s Mailbox. This program records the message and triggers post-dispatch hooks such as an IGP Hook to charge and account for gas on the destination, and a Merkle Tree Hook to append the message to a Merkle tree whose root will later be signed by validators. Validators watch the Mailbox, compute Merkle roots over dispatched messages, sign these roots, and make these signatures available for the relayers. An off-chain relayer can then fetch the signed Merkle root and the corresponding message, and then provide these to the process function on the destination chain’s Mailbox. During that call, the relayer will additionally pass the address of an Interchain Security Module (ISM) that specifies verification rules for the message to be considered valid (e.g., what validator quorum is required). The Mailbox then delegates verification to the ISM, and on success, invokes the destination application to apply the message.

Lastly, it’s important to note that the architecture of Hyperlane’s Aleo integration differs slightly from the standard Hyperlane protocol due to constraints imposed by the Leo programming language. For instance, to dispatch messages, applications on Aleo don’t call dispatch directly on the mailbox but rather on a dedicated dispatch_proxy program. However, these Aleo-specific differences are not really relevant to this audit, so we omit them here. For a more detailed account on this topic, we refer the reader to our previous audit report for Hyperlane’s Aleo integration.
The hyp_multisig Program
The hyp_multisig program represents the multisig-controlled governance layer of Hyperlane’s core programs on Aleo. More specifically, it will become the owner of the mailbox, the ism_manager, and the hook_manager. Once in place, all privileged operations on these programs are routed through hyp_multisig and are only executed if a corresponding multisig operation has been correctly initialized and fully signed via multisig_core. The high-level usage pattern is as follows:
- Wallet Setup
After deployment,
initis called to create a wallet inmultisig_corewith a specified threshold and signer set. The correspondingwallet_idis deterministically derived fromself.address. - Operation Initialization
To initialize a multisig operation, an admin proposes by calling
init_multisig_opand providing asigning_op_id, an expiration block, and anop::Opstruct that encodes what will eventually be executed (e.g., “set the default ISM to address X”). - Signing (off-program, in
multisig_core) The signers sign the operation withmultisig_coretracking the signatures and completion status. - Execution
When enough signatures have been collected, an executor can call the corresponding
exec_*transition (e.g.,exec_mailbox_set_default_ism) to execute the proposed multisig operation.
Using this pattern, the following Hyperlane admin actions will be gated by multisig:
Mailbox
set_dispatch_proxyset_ownerset_default_ismset_default_hookset_required_hook
ISM Manager
set_domainremove_domaintransfer_routing_ism_ownership
Hook Manager
set_destination_gas_configremove_destination_gas_configtransfer_igp_ownershipclaim
The hook manager’s claim will send accumulated fees to the hyp_multisig program. To withdraw these funds, admins can use the exec_credits_transfer_to_caller transition, provided they first initiated and signed a corresponding multisig operation.
Lastly, the hyp_multisig program has a @custom constructor which enforces that program upgrades are gated by multisig: for editions beyond the initial deployment (i.e., self.edition > 0), the constructor checks that an associated signing operation has been completed in multisig_core.
The hyp_warp_multisig Program
Hyperlane Warp Routes (HWRs) are cross-chain asset bridges that enable the transfer of tokens between chains using Hyperlane. Developers can permissionlessly deploy HWRs to move assets between chains. Hyperlane’s Aleo integration currently provides three different program templates that can be used to create HWRs. These are:
- The
hyp_nativetemplate. This can be used to interact with the native currency of Aleo, i.e., thecreditsprogram. - The
hyp_synthetictemplate. This enables bridging of synthetic (wrapped) representations of external assets on Aleo. On inbound transfers, synthetic tokens are minted to mirror the origin chain asset. On outbound transfers, they are burned before dispatch. - The
hyp_collateraltemplate. This enables bridging of existing assets that are already registered in thetoken_registryprogram. On inbound transfers, tokens are transferred from thehyp_collateralprogram to the recipient. On outbound transfers, they are transferred from the sender to thehyp_collateralprogram before dispatch.
The hyp_warp_multisig represents the interface program between multisig_core and any one of the above warp-token programs. This way, all admin-level operations on a given warp token can be gated by multisig logic. Developers will have to deploy an instance of hyp_warp_multisig for each warp token they are deploying.
The usage of hyp_warp_multisig follows the same “Setup-OpInit-Signing-Execution” pattern as in hyp_multisig, which is why we don’t repeat it here.
The specific warp-token actions that can be multisig-gated by hyp_warp_multisig are:
set_custom_hookset_custom_ismset_ownerenroll_remote_routerunroll_remote_router
As with hyp_multisig, the constructor enforces multisig-based upgrades: for program editions beyond the initial deployment, it checks that the upgrade has been approved as a completed signing operation in multisig_core.
Compliant Token Template
This token program is a token that allows addresses to transfer tokens between accounts, supporting public to public, public to private, private to public and private to private transfers.
In addition to the privacy-preserving transfers, the program has its compliance enforced with a freeze list, where frozen accounts cannot move funds. The latest pull request has multisig supported, where a completed signing request is required in order to:
- Upgrade the compliant token program to the next edition,
- Update the role of a wallet or an address, given that the operating wallet has the
MANAGER_ROLE, - Mint publicly or privately given that the operating wallet has the
MINTER_ROLE, - Burn publicly or privately given that the operating wallet has the
BURNER_ROLE, - Pause (or unpause) the compliant token program, which disables (resp. enables) the exchange of tokens, given that the operating wallet has the
PAUSE_ROLE.
Except program upgrade, each of the other functions already had a counterpart that allows an address with appropriate roles to perform the same action.
Freeze List
The freeze list is maintained as an ordered Merkle tree of frozen addresses in sealance_freezelist_registry.leo. Multisig is enabled in the latest pull request, where the below features are implemented:
- Upgrade the freeze list program to the next edition,
- Update the roles of a wallet or an address, given that the operating wallet has the
MANAGER_ROLE, - Update the block height window given that the operating wallet has the
FREEZELIST_MANAGER_ROLE, and - Update the freeze list, given that the operating wallet has the
FREEZELIST_MANAGER_ROLE.
Bridge Program
The bridge program (circle_bridge.aleo) implements the integration of Circle’s XReserve protocol, enabling minting and burning of wrapped USDC in a way consistent with Circle’s attestation model. At its core, the contract processes deposit payloads signed by Circle, verifies freeze-list requirements, ensures replay protection through a deposit nonce, and initiates mint or burn operations in the downstream bridged_usdc.aleo program, which based from Compliant Token Template.
The integration of multisig in the current audit is to gate administrative actions behind multisignature approvals, which enforces correct binding, expiry, and role authorization before applying changes.
There are three administrative operations that utilize multisig:
- Pause bridge: Pause/unpause bridge by the pause admin role.
- Update Circle attester: Rotate and update Circle attester key used for ECDSA verification.
- Update role: Allows reassignment of wallet roles by the manager role.
In addition to those administrative operations, the multisig is also used to gate program upgrades as explained in the multisig program upgrades section.