name: "ref-lifecycle" description: "Type Thought-template (instantiate before use) - Trigger Pattern Always (Aptos Move) -- ConstructorRef/TransferRef/MintRef/BurnRef lifecycle"
Skill: Reference Lifecycle Analysis
Type: Thought-template (instantiate before use) Trigger Pattern: Always (Aptos Move) -- ConstructorRef/TransferRef/MintRef/BurnRef lifecycle Inject Into: Breadth agents, depth-state-trace, depth-token-flow Research basis: Aptos Object model capability-based access control, permanent reference semantics
Background
In Aptos Move, object capabilities (Refs) are unforgeable tokens that grant specific permissions over objects. Unlike role-based access control in EVM, Refs are permanent once created -- they CANNOT be revoked. A leaked or improperly stored Ref grants permanent capability to its holder.
Key Ref types:
- ConstructorRef: Created once during
object::create_*. Parent of all other Refs. Grants ability to generate TransferRef, MintRef, BurnRef, DeleteRef, and ExtendRef. - TransferRef: Grants ability to transfer an object even when its
TransferRefis frozen. Bypassesungated_transferrestrictions. - MintRef: Grants ability to mint FungibleAsset. Unlimited minting if held.
- BurnRef: Grants ability to burn FungibleAsset from any FungibleStore.
- DeleteRef: Grants ability to delete an object.
- ExtendRef: Grants ability to generate a signer for the object, enabling further resource manipulation.
Trigger Patterns
ConstructorRef|TransferRef|MintRef|BurnRef|DeleteRef|ExtendRef|
object::create_named_object|object::create_sticky_object|object::create_object|
fungible_asset::generate_mint_ref|fungible_asset::generate_burn_ref|
fungible_asset::generate_transfer_ref|object::generate_delete_ref|
object::generate_extend_ref|object::generate_transfer_ref
Reasoning Template
Step 1: Reference Inventory
Enumerate ALL Ref types found in the codebase. For each:
| Ref Type | Created In (module::function) | Stored Location | Access Control | Capability Granted |
|---|---|---|---|---|
| ConstructorRef | {module}::{init_fn} | {consumed / stored in resource} | {who can access} | Generate all other Refs |
| MintRef | {module}::{init_fn} | {global resource at @addr} | {who can access} | Unlimited minting of {asset} |
| BurnRef | {module}::{init_fn} | {global resource at @addr} | {who can access} | Burn {asset} from any store |
| TransferRef | {module}::{init_fn} | {global resource at @addr} | {who can access} | Transfer {asset} bypassing freeze |
| DeleteRef | {module}::{init_fn} | {global resource at @addr} | {who can access} | Delete {object} |
| ExtendRef | {module}::{init_fn} | {global resource at @addr} | {who can access} | Generate signer for {object} |
Completeness check: Search for ALL generate_*_ref calls and object::create_* calls. Every Ref created MUST appear in the table.
Step 2: ConstructorRef Analysis
The ConstructorRef is the root capability. It exists only during the init_module or object creation call.
Check 2a: Is ConstructorRef stored?
- Search for any struct field of type
ConstructorRef-- this type hasdropbut NOTstore, so it CANNOT be stored in global storage directly. - If code attempts to extract a signer from ConstructorRef via
object::generate_signer(&constructor_ref)and stores the signer reference indirectly, trace what that signer can do. - Expected pattern: ConstructorRef is consumed during init to generate other Refs, then dropped. It should NOT persist beyond the creation transaction.
Check 2b: What Refs are generated from it?
- List every
generate_*_refcall that uses this ConstructorRef - For each generated Ref: is it stored with appropriate access control?
- FINDING trigger: If ConstructorRef generates MintRef AND that MintRef is stored with
publicvisibility or weak access control -> unlimited minting capability leak.
Check 2c: ExtendRef derived signer
- If
object::generate_extend_refis called, the resulting ExtendRef can later produce a signer viaobject::generate_signer_for_extending - Trace ALL uses of this derived signer -- it can move resources, modify object state, and call
move_to/move_from - FINDING trigger: If ExtendRef is stored with weaker access control than the operations its signer can perform.
Step 3: MintRef / BurnRef Analysis
Check 3a: Storage access control
- Where is MintRef stored? (must be in a resource at a controlled address)
- Who can call functions that borrow the MintRef? (check
acquiresand signer requirements) - Is there any
public funthat exposes MintRef via return value or mutable reference? - FINDING trigger:
public funreturning&MintRefor&mut MintRef= capability leak to any module.
Check 3b: Mint amount validation
- Does the minting function validate the amount? (cap, rate limit, per-epoch limit)
- Is there a supply cap enforced? (
fungible_asset::supplycheck before mint) - FINDING trigger: Unlimited minting with no cap = inflation vulnerability.
Check 3c: BurnRef scope
fungible_asset::burn_fromwith a BurnRef can burn tokens from ANY FungibleStore- Check: does the burn function require the store owner's authorization, or only the BurnRef?
- FINDING trigger: If BurnRef holder can burn from arbitrary user stores without authorization.
Check 3d: Mint/Burn symmetry
- If protocol has both MintRef and BurnRef: are they held by the same entity?
- Can one be used without the other? (mint without ability to burn = permanent inflation; burn without mint = permanent deflation)
- Are there economic invariants that depend on mint/burn balance?
Step 4: TransferRef Analysis
Check 4a: Freeze bypass
fungible_asset::transfer_with_refbypasses frozen store checks- If the protocol uses
fungible_asset::set_frozen_flagfor compliance/security: does a stored TransferRef undermine the freeze? - FINDING trigger: TransferRef stored alongside freeze functionality = freeze can always be bypassed by TransferRef holder.
Check 4b: Transfer direction
- Can TransferRef be used to transfer FROM any store (withdrawal) or only TO (deposit)?
fungible_asset::transfer_with_reftakesfrom: Object<FungibleStore>andto: Object<FungibleStore>-- the holder controls BOTH ends- FINDING trigger: TransferRef holder can drain any FungibleStore of the associated asset.
Check 4c: Who holds TransferRef?
- If protocol stores TransferRef: who can invoke the transfer function?
- Is there a path where an external caller (not admin) can trigger a TransferRef-backed transfer?
- Trace all call paths from
public entry funto thetransfer_with_refinvocation.
Step 5: DeleteRef Analysis
Check 5a: Resource cleanup before deletion
- If
object::delete(delete_ref)is called, what happens to resources stored at the object address? - Move does NOT automatically clean up resources when an object is deleted -- resources become orphaned
- FINDING trigger: Object deletion without prior
move_fromof all resources = stranded assets (Rule 9: minimum MEDIUM).
Check 5b: Deletion authorization
- Who holds the DeleteRef? Can they delete an object that other users depend on?
- Is there a dependency check before deletion? (e.g., are there outstanding balances, active positions?)
- FINDING trigger: DeleteRef holder can delete a shared object (LP pool, vault) = griefing or fund loss.
Step 6: Ref Leakage Path Analysis
Check 6a: Public function returns
- Search for ANY
public funorpublic(friend) funthat returns a Ref type - Even
&MintRef(immutable reference) leak is dangerous because it can be passed tofungible_asset::mintwithin the same transaction - Leakage severity:
public funreturning Ref = Critical leak (any module can use).public(friend) funreturning Ref = Medium leak (friend modules can use -- check friend list).
Check 6b: Friend module exposure
- List all
frienddeclarations in modules that store Refs - For each friend module: does it re-export the Ref or expose a
public funthat uses the Ref without additional access control? - Transitive leak: Module A stores MintRef, Module B is friend of A and gets MintRef access, Module B has
public funthat calls Module A's mint function = any module can mint via Module B.
Check 6c: Store ability check
- Refs with
storeability can be placed in arbitrary global storage locations - Check: do any Ref types in the protocol have
store? (standard Aptos Refs: ConstructorRef hasdroponly; MintRef/BurnRef/TransferRef/DeleteRef/ExtendRef havedropandstore) - FINDING trigger: Ref with
storeability placed in a resource with weak access control = Ref can migrate to uncontrolled storage.
Step 7: Ref Revocation Assessment
Critical fact: Aptos Refs CANNOT be revoked once created. There is no revoke_mint_ref function in the framework.
Check 7a: Maximum blast radius
- For each stored Ref: what is the maximum damage if the Ref holder is compromised?
- Document: if MintRef is compromised -> unlimited inflation. If TransferRef is compromised -> drain all stores. If ExtendRef is compromised -> arbitrary object state modification.
Check 7b: Compensating controls
- Since Refs cannot be revoked, does the protocol have compensating controls?
- Pause mechanism that blocks functions using the Ref?
- Multi-signer requirement before Ref-backed operations?
- Rate limiting on Ref-backed operations?
- FINDING trigger: No compensating controls on a stored Ref with high blast radius = single point of failure.
Check 7c: Module upgrade path
- If the module is upgradeable (
compatibleorimmutablepolicy?): can an upgrade change who accesses the Ref? - If the module is immutable: the Ref access pattern is permanent -- any vulnerability is permanent.
Step 8: Cross-Ref Interaction
Check 8a: Ref combination attacks
- Can MintRef + TransferRef be combined? (Mint tokens, then force-transfer them to a target store)
- Can BurnRef + TransferRef be combined? (Transfer tokens from victim store, then burn the evidence)
- Can ExtendRef + any other Ref be combined? (Generate signer to bypass access control, then use Ref)
Check 8b: Ref holder alignment
- Are all Refs held by the same entity? If different entities hold different Refs, model adversarial interaction.
- Example: Admin holds MintRef, Operator holds TransferRef. If Operator is compromised, they can drain stores. Admin cannot revoke TransferRef.
Finding Template
## Finding [{PREFIX}-N]: {Title}
**Verdict**: CONFIRMED / PARTIAL / REFUTED / CONTESTED
**Step Execution**: {see checklist below}
**Ref Type**: {ConstructorRef / MintRef / BurnRef / TransferRef / DeleteRef / ExtendRef}
**Severity**: {Critical/High/Medium/Low/Info}
**Location**: {SourceFile:LineN}
**Description**: {What capability is exposed and how}
**Impact**: {What an attacker/compromised entity can do with the Ref}
**Evidence**: {Code showing Ref creation, storage, and access path}
### Blast Radius
- **If compromised**: {Maximum damage description}
- **Revocable**: NO (Aptos Refs are permanent)
- **Compensating controls**: {pause/multisig/rate-limit or NONE}
Step Execution Checklist (MANDATORY)
| Step | Required | Completed? | Notes |
|---|---|---|---|
| 1. Reference Inventory | YES | Y/N/? | Must enumerate ALL Refs |
| 2. ConstructorRef Analysis | YES | Y/N/? | |
| 3. MintRef/BurnRef Analysis | IF present | Y/N(none)/? | |
| 4. TransferRef Analysis | IF present | Y/N(none)/? | |
| 5. DeleteRef Analysis | IF present | Y/N(none)/? | |
| 6. Ref Leakage Path Analysis | YES | Y/N/? | Check public returns + friends |
| 7. Ref Revocation Assessment | YES | Y/N/? | Always: Refs are permanent |
| 8. Cross-Ref Interaction | IF 2+ Ref types | Y/N(single)/? |
Output Format for Step Execution
**Step Execution**: check1,2,3,4,6,7,8 | x5(no DeleteRef)
OR if incomplete:
**Step Execution**: check1,2,3 | ?4,6,7(TransferRef not fully traced)
**FLAG**: Incomplete analysis -- requires depth review (leakage paths not exhausted)
Instantiation Parameters
{CONTRACTS} -- Move modules to analyze
{ASSET_NAME} -- Primary fungible asset name
{REF_STORAGE} -- Where Refs are stored (resource name and address)
{ACCESS_CONTROL} -- Who can access stored Refs (signer requirements)
{FRIEND_MODULES} -- Modules declared as friends
{FREEZE_USED} -- Whether protocol uses freeze functionality (YES/NO)
{UPGRADE_POLICY} -- Module upgrade policy (compatible/immutable)
Output Schema
| Field | Required | Description |
|---|---|---|
| ref_inventory | yes | Complete table of all Refs in codebase |
| constructor_ref_analysis | yes | ConstructorRef lifecycle and consumption |
| mint_burn_analysis | if present | MintRef/BurnRef storage and access control |
| transfer_ref_analysis | if present | TransferRef and freeze bypass potential |
| delete_ref_analysis | if present | DeleteRef and resource cleanup |
| leakage_paths | yes | Public/friend exposure of Refs |
| revocation_assessment | yes | Blast radius and compensating controls |
| cross_ref_interactions | if 2+ types | Combined Ref attack scenarios |
| finding | yes | CONFIRMED / REFUTED / CONTESTED / NEEDS_DEPTH |
| evidence | yes | Code locations with line numbers |
| step_execution | yes | Status for each step |