Trigger Pattern Protocol has privileged capabilities (AdminCap, OwnerCap, UpgradeCap, TreasuryCap, custom caps) - Inject Into Breadth agents (optional), depth-state-trace
Scanned 9/6/2026
Install to Claude Code
npx -y skills add PlamenTSV/plamen --skill centralization-risk --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Centralization Risk?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/plamentsv-centralization-risk-9af0a6be)More formats (shields.io, HTML) on the badges page.
---
name: "centralization-risk"
description: "Trigger Pattern Protocol has privileged capabilities (AdminCap, OwnerCap, UpgradeCap, TreasuryCap, custom caps) - Inject Into Breadth agents (optional), depth-state-trace"
---
# Skill: CENTRALIZATION_RISK (Sui)
> **Trigger Pattern**: Protocol has privileged capabilities (AdminCap, OwnerCap, UpgradeCap, TreasuryCap, custom caps)
> **Inject Into**: Breadth agents (optional), depth-state-trace
> **Finding prefix**: `[CR-N]`
> **Rules referenced**: R2, R6, R9, R10, R13
> **Required**: NO (recommended when protocol has 3+ distinct privileged capability types)
Covers: single points of failure, privilege escalation, capability object management, external governance dependencies, emergency powers. On Sui, centralization risk has unique dimensions: capability objects (AdminCap) are first-class owned objects that can be transferred, UpgradeCap controls full package replacement, TreasuryCap controls token supply, and shared objects can be the target of admin-gated mutations. The ownership and lifecycle of capability objects IS the access control model.
---
## Trigger Patterns
```
AdminCap|OwnerCap|UpgradeCap|TreasuryCap|GovernanceCap|OperatorCap|PauserCap|MinterCap|
Cap\b|_cap|admin|authority|privilege
```
---
## Step 1: Capability Inventory
Enumerate ALL capability objects and ALL functions requiring capabilities:
| # | Capability Type | Module | Abilities | Created Where | Holder | What It Controls | Impact If Lost/Stolen |
|---|----------------|--------|-----------|---------------|--------|------------------|----------------------|
| 1 | {CapType} | {module} | {key, store, ...} | {init or func} | {address/shared} | {list functions} | {worst case} |
**Key question for each capability**: Is it OWNED (by a single address) or SHARED (accessible via reference in any transaction)?
- **Owned AdminCap**: Only the owner can pass it as a tx argument. Strongest access control, but single point of failure.
- **Shared config with admin field**: Admin address stored in shared object. More flexible but requires `assert!(sender == admin)` checks -- verify these are present on ALL admin functions.
- **Shared capability object**: DANGEROUS -- anyone can pass a shared `AdminCap` as a transaction argument without ownership.
**Categorize each by impact**:
- **FUND_CONTROL**: Can move, lock, or destroy user funds (e.g., emergency withdraw, treasury drain)
- **PARAMETER_CONTROL**: Can change fees, rates, thresholds, delays (e.g., set_fee, set_max_leverage)
- **OPERATIONAL_CONTROL**: Can pause, unpause, add/remove pools, whitelist/blacklist
- **UPGRADE_CONTROL**: UpgradeCap -- controls package upgrades, policy changes
- **MINT_CONTROL**: TreasuryCap -- controls token supply (mint/burn)
**Sui-specific ability checks**:
- Does the capability have `store` ability? If YES -> anyone holding it can `public_transfer` it, meaning the privilege is freely transferable. Is this intentional?
- Does the capability have `drop` ability? If YES -> it can be silently discarded. For AdminCap, dropping it means admin functions become permanently uncallable. For UpgradeCap, dropping makes the package permanently immutable.
- Is the capability created ONLY in `init()`? If created elsewhere, can unauthorized parties mint new capabilities?
---
## Step 2: Capability Hierarchy and Separation
Map the capability hierarchy:
| Capability | Created By | Can Create Other Caps? | Transferable (has `store`)? | Destructible (has `drop`)? | Timelock/Delay? |
|-----------|-----------|----------------------|---------------------------|---------------------------|-----------------|
| {cap} | {init / admin_func} | YES/NO | YES/NO | YES/NO | YES/NO |
**Check**:
- [ ] Are FUND_CONTROL and UPGRADE_CONTROL separated into different capability types?
- [ ] Does any single capability type grant both PARAMETER_CONTROL and FUND_CONTROL?
- [ ] Are capability transfers behind timelocks or governance mechanisms?
- [ ] Can capabilities be destroyed, and what happens when they are?
- [ ] Is there a master capability that can create all other capabilities?
**Sui-specific separation patterns**:
- Best practice: UpgradeCap held by governance multisig, AdminCap held by operations team, TreasuryCap held by treasury
- Anti-pattern: single `init` function creates ALL caps and transfers them to `tx_context::sender()` -- single point of failure at deployment
- Two-step transfer: propose new admin -> new admin accepts. Prevents accidental transfer to wrong address.
### UpgradeCap Analysis (CRITICAL)
| Package | UpgradeCap Holder | Upgrade Policy | Destroyed? | Risk Level |
|---------|------------------|---------------|-----------|------------|
| {package_id} | {address or description} | {compatible/additive/dep_only} | YES (immutable) / NO | {assessment} |
**Risk levels**:
- **UpgradeCap destroyed (`make_immutable`)**: No upgrade risk.
- **UpgradeCap held by governance multisig with timelock**: Low risk.
- **UpgradeCap held by multisig (no timelock)**: Low-Medium risk.
- **UpgradeCap held by single address**: **CRITICAL** risk -- one compromised key replaces entire package. All shared objects now interact with attacker code.
- **UpgradeCap stored in shared object**: Check access control carefully. If extraction is possible -> same as single address risk.
---
## Step 3: Single Points of Failure
For each capability type:
| Capability | Key Compromise Impact | Current Protection | Residual Risk |
|-----------|----------------------|-------------------|---------------|
| {cap} | {what attacker can do with it} | {multisig holder? timelock wrapper?} | {what remains} |
### Sui-Specific SPOF Analysis
| Risk | Description | Severity |
|------|-------------|----------|
| **UpgradeCap compromise** | Attacker publishes malicious upgrade. All shared objects now interact with attacker code. ALL user funds at risk. | CRITICAL if single address, HIGH if multisig without timelock |
| **AdminCap compromise** | Attacker calls admin functions: drain pools, change parameters, pause protocol. | HIGH if AdminCap controls fund extraction |
| **TreasuryCap compromise** | Attacker mints unlimited tokens, diluting all holders. | HIGH if supply-sensitive protocol |
| **AdminCap with `store`** | Holder (or compromised key) can transfer AdminCap to anyone via `public_transfer`. New holder has full admin access. | Adds transfer risk to any compromise scenario |
| **AdminCap with `drop`** | Admin can accidentally destroy the capability. Admin functions become permanently uncallable. | MEDIUM -- permanent loss of admin access (Rule 9 if admin functions needed for user fund recovery) |
| **Phantom ownership** | Capability transferred to an address nobody controls (e.g., `@0x0`). Object is permanently inaccessible -- equivalent to destroying it. | Same as destruction if holding value or needed for operations |
**Severity assessment**:
- Single address with FUND_CONTROL or UPGRADE_CONTROL -> **HIGH** (minimum)
- Multisig holds capability + timelock -> **LOW** (but document)
- UpgradeCap destroyed + no admin fund extraction -> **INFO**
---
## Step 4: External Governance Dependencies
Identify parameters or behaviors controlled by EXTERNAL governance:
| Dependency | External Entity | What They Control | Protocol Impact If Changed | Notification? |
|------------|----------------|-------------------|---------------------------|---------------|
| {dep} | {entity} | {parameter/behavior} | {impact} | YES/NO |
**Sui-specific external governance**:
- **Sui framework upgrades**: Validators upgrade `sui::*` packages via governance. Can framework changes break this protocol?
- **Oracle provider changes**: If protocol reads from oracle shared object, oracle admin can change prices, feeds, or parameters
- **DeFi protocol governance**: External pools, vaults, or DEXes may change parameters
- **Bridge governance**: Wormhole guardian set rotation, Sui Bridge committee changes
- **Dependency package upgrades**: If a dependency has active UpgradeCap, its owner can publish new versions. Our package pins to specific version at compile time, but compatible upgrades preserve types that we import.
**Check**:
- Can external governance changes break protocol invariants?
- Does the protocol have circuit breakers for external changes?
- **Does the protocol verify external package addresses at call sites?** Types from compatible-upgraded packages remain the same, but behavior may change.
---
## Step 5: Emergency Powers
Document emergency/pause capabilities:
| Emergency Function | Required Capability | What It Affects | Recovery Path | Time to Recover |
|-------------------|-------------------|-----------------|---------------|-----------------|
| {func} | {cap_type} | {scope: all operations / specific pool} | {how to resume} | {estimate} |
### Sui Emergency Patterns
| Pattern | Description | Risk |
|---------|-------------|------|
| **Global pause field** | Shared config object has `paused: bool`. All user functions check it. | Standard -- check: can users withdraw when paused? |
| **Capability destruction** | Admin destroys their own capability to "renounce" control. | Irreversible -- if needed later for recovery, funds stranded |
| **Object freeze** | Admin calls `transfer::public_freeze_object` on a config. Permanent immutability. | If done to wrong object, permanent loss of admin access |
| **Package policy tightening** | UpgradeCap holder restricts policy (compatible -> additive -> immutable). | Good for security, but irreversible. Cannot loosen policy. |
**Check**:
- [ ] Can pausing strand user funds permanently? (Rule 9 -- stranded asset severity floor: minimum MEDIUM)
- [ ] Is there a maximum pause duration or automatic unpause?
- [ ] Can users emergency-withdraw during pause?
- [ ] What happens if the PauserCap/AdminCap is lost or destroyed?
- [ ] Can the protocol be permanently bricked by destroying a critical capability?
- [ ] If no exit during pause -> apply Rule 9 (minimum MEDIUM)
---
## Output Schema
```markdown
## Finding [CR-N]: Title
**Verdict**: CONFIRMED / PARTIAL / REFUTED
**Step Execution**: check1,2,3,4,5 | skip(reason) | uncertain
**Rules Applied**: [R2:___, R6:___, R9:___, R10:___, R13:___]
**Severity**: Critical/High/Medium/Low/Info
**Location**: sources/{module}.move:LineN
**Centralization Type**: FUND_CONTROL / PARAMETER_CONTROL / OPERATIONAL_CONTROL / UPGRADE_CONTROL / MINT_CONTROL
**Affected Capability**: {cap_type}
**Mitigation Present**: {multisig / timelock / UpgradeCap destroyed / governance / NONE}
**Description**: What is wrong
**Impact**: What can happen if capability is compromised, lost, or holder acts maliciously
**Recommendation**: How to mitigate (destroy UpgradeCap, use multisig, add timelock, remove `store` ability, wrap in governance)
```
---
## Step Execution Checklist (MANDATORY)
| Step | Required | Completed? | Notes |
|------|----------|------------|-------|
| 1. Capability Inventory (all cap-gated functions) | YES | | Owned vs shared, abilities checked |
| 2. Capability Hierarchy and Separation | YES | | `store`/`drop` analysis, UpgradeCap assessment |
| 3. Single Points of Failure (per capability) | YES | | |
| 4. External Governance Dependencies | YES | | |
| 5. Emergency Powers and Recovery Paths | YES | | |
### Cross-Reference Markers
**After Step 1**: Cross-reference with ABILITY_ANALYSIS Section 4 (Capability Pattern Audit) -- capabilities with `store` enable unrestricted transfer.
**After Step 2**: If UpgradeCap held by single address -> immediate finding (minimum HIGH).
**After Step 3**: If AdminCap has `drop` and is needed for fund recovery -> Rule 9 stranded asset finding.
**After Step 5**: If no emergency withdraw exists AND pause is possible -> Rule 9 stranded asset finding.
**After Step 5**: If protocol claims trustlessness but retains UpgradeCap/AdminCap -> Rule 13 anti-normalization finding.
If any step skipped, document valid reason (N/A, no external governance, no emergency functions, single capability only).
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!