Agent skill
external-precondition-audit
Trigger Pattern Any external package function call detected in program - Inject Into Breadth agents (merged via M5 hierarchy)
Install this agent skill to your Project
npx add-skill https://github.com/PlamenTSV/plamen/tree/main/agents/skills/sui/external-precondition-audit
SKILL.md
Skill: External Precondition Audit (Sui)
Trigger Pattern: Any external package function call detected in program Inject Into: Breadth agents (merged via M5 hierarchy) Finding prefix:
[EPA-N]Rules referenced: R1, R4, R8, R10 Constraint: Interface-level inference only -- no production fetch required
use.*external|friend|public.*package|transfer::public_|dynamic_field|coin::from_balance|
clock::timestamp_ms|sui::pay|dex|swap|oracle|price_feed
For every external package the protocol calls:
1. Interface-Level Requirement Inference
From the imported module signatures, infer what the external package requires:
| External Function Called | Parameters Passed | Likely Preconditions (from signature) | Our Protocol Validates? | Package Immutable? |
|---|
Inference method: Read the function signature, type constraints, and any doc comments. Example: pool::swap<A, B>(pool: &mut Pool<A, B>, coin_in: Coin<A>, ...) -> infer that pool must be the correct pool for A/B pair, coin_in must have sufficient balance, and return Coin<B> may have zero value (slippage).
Package immutability check (CRITICAL Sui-specific):
- Is the external package immutable (
UpgradeCapdestroyed)? - If upgradeable: who holds the
UpgradeCap? What upgrade policy (compatible, additive, dependency-only)? - If upgradeable with
compatiblepolicy: the external package can change function behavior arbitrarily. Apply Rule 4 (adversarial assumption) -- treat the external package as potentially malicious after upgrade. - If immutable: behavior is fixed, trust boundary is clear.
2. Return Value Consumption
| External Call | Return Type | How Protocol Uses Return | Failure Mode if Return Unexpected |
|---|
For each return value:
- What happens if it returns a
Coin<T>with zero balance? (division by zero, incorrect share calculation) - What happens if it returns a
Coin<T>with less value than expected? (slippage not checked) - What happens if the call aborts? (entire PTB aborts -- can this be used for griefing?)
- Hot potato returns: If the external call returns a hot potato (zero-ability struct), is the consuming function always reachable in the same PTB? If not, the PTB always aborts.
Sui-specific: External package calls within a PTB share the same abort scope. If any external call aborts, the entire PTB reverts. Model: can an attacker cause an external call to abort to grief a user's multi-step PTB?
- For each external data structure received (Vec, array, Map, list): (a) What ordering/uniqueness does the consuming code assume? (b) Does the external contract's spec guarantee that ordering? (c) What happens if the assumption is violated (unsorted, duplicates, gaps)?
3. State Dependency Mapping
| Protocol State | Depends on External Shared Object | External State Can Change Between Epochs/Txns? |
|---|
For each dependency: model what happens when the external shared object state changes between our protocol's transactions.
Sui-specific concerns:
- Shared objects are ordered by consensus. Two transactions touching the same shared object are serialized. But transactions touching DIFFERENT shared objects can execute concurrently.
- If our protocol reads shared object A (external) and then writes shared object B (ours), another transaction can modify A between our read and our next access.
- Cross-epoch state: External shared objects may have epoch-dependent behavior (e.g., staking pools that update per epoch). Is our protocol aware of epoch boundaries?
- Package upgrade state change: If the external package upgrades, shared objects created by the old version may behave differently when accessed by functions from the new version. Does our protocol pin to a specific package version?
3b. Package Upgrade Risk Assessment
For each external package dependency:
| External Package | UpgradeCap Status | Upgrade Policy | Impact if Upgraded | Our Protocol's Mitigation |
|---|---|---|---|---|
| {package} | {destroyed (immutable) / held by {who}} | {compatible / additive / dep_only / immutable} | {behavior change risk} | {version pin / none} |
Check:
- Does the external package use
sui::package::UpgradeCap? If so:- Who holds the
UpgradeCap? (single admin, multisig, destroyed for immutability) - What upgrade policy is set? (
compatible= can change anything,additive= can add but not change,dep_only= only dependency updates,immutable= frozen forever) - Can an upgrade change the behavior of functions our protocol depends on?
- Who holds the
- Does our protocol pin to a specific package version, or does it follow upgrades automatically?
- If the external package upgrades with
compatiblepolicy: shared objects created by the old version may behave differently when accessed by the new version's functions. Our protocol may call into changed behavior without any code change on our side.
Finding Template
**ID**: [EPA-N]
**Verdict**: CONFIRMED / PARTIAL / REFUTED / CONTESTED
**Step Execution**: (see checklist below)
**Rules Applied**: [R1:___, R4:___, R8:___, R10:___]
**Severity**: Critical/High/Medium/Low/Info
**Location**: sources/{module}.move:LineN
**Title**: {missing external validation / unexpected return / state dependency}
**Description**: {specific issue with code reference}
**Impact**: {what attacker can achieve via the external package weakness}
Step Execution Checklist (MANDATORY)
| Section | Required | Completed? | Notes |
|---|---|---|---|
| 1. Interface-Level Requirement Inference | YES | Includes package immutability check | |
| 2. Return Value Consumption | YES | Hot potato return paths checked | |
| 3. State Dependency Mapping | YES | Cross-epoch + package upgrade state | |
| 3b. Package Upgrade Risk | YES | UpgradeCap holder + upgrade policy |
If any step skipped, document valid reason (N/A, no external packages, framework-only deps).
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
integration-hazard-research
Protocol Type Trigger NAMED_EXTERNAL_PROTOCOL (detected when recon finds import/interface for an identifiable external protocol — not standard libraries). Researches known integration hazards of the target protocol.
outcome-determinism
Protocol Type Trigger outcome_determinism - detected when EITHER of these code patterns are present - - Selection from finite depletable pool with fallback behavior (while(full)...
governance-attack-vectors
Protocol Type Trigger governance (detected when Governor, Timelock, voting, proposal, quorum, delegate patterns found) - Inject Into Breadth agents, depth-external, depth-edge-case
vault-accounting
Protocol Type Trigger vault (detected in recon TASK 0 Step 1) - Inject Into Core state agent OR economic design agent (merge via M4 hierarchy)
lending-protocol-security
Protocol Type Trigger lending (detected when recon finds liquidate|borrow|repay|collateral|lend|loan|LTV|healthFactor|interestRate|debtToken) - Inject Into Breadth agents, depth...
dex-integration-security
Protocol Type Trigger dex_integration (detected when recon finds swap|addLiquidity|removeLiquidity|IUniswapV2Router|ISwapRouter|amountOutMin|amountOutMinimum|slippage - AND the...
Didn't find tool you were looking for?