Agent skill
dependency-audit
Trigger Pattern EXTERNAL_LIB flag (third-party Move dependencies detected in Move.toml beyond Sui framework) - Inject Into Breadth agents, depth-external
Install this agent skill to your Project
npx add-skill https://github.com/PlamenTSV/plamen/tree/main/agents/skills/sui/dependency-audit
SKILL.md
Skill: DEPENDENCY_AUDIT (Sui/Move)
Trigger Pattern: EXTERNAL_LIB flag (third-party Move dependencies detected in Move.toml beyond Sui framework) Inject Into: Breadth agents, depth-external Finding prefix:
[DEP-N]Rules referenced: R1, R4, R8, R10
Move's dependency model is package-based: Move.toml declares dependencies with git URLs and revisions. Unlike EVM's compiled-and-deployed model where dependencies are inlined at compile time, Sui Move packages can depend on other PUBLISHED packages (on-chain) or source packages (compiled together). Third-party math libraries, utility packages, and protocol SDKs are common dependency vectors.
STEP PRIORITY: Steps 3 (Critical Function Audit, especially Step 4 Math Library Audit) and 5 (Shared Object Dependencies) are where HIGH/CRITICAL severity findings most commonly hide. The Cetus hack originated from a custom math library bit shift bug. Do NOT rush these steps.
Trigger Patterns
[dependencies]|git\s*=|subdir\s*=|rev\s*=|published-at|math|utils|library|helpers|common
Step 1: Dependency Inventory
Parse Move.toml and build a complete dependency tree. Categorize:
| # | Dependency Name | Source Type | Source URL/Address | Version/Rev Pinned? | Trust Level | Upgrade Risk |
|---|---|---|---|---|---|---|
| 1 | Sui | Framework | sui framework | Validator-controlled | TRUSTED | Framework upgrade by validators |
| 2 | MoveStdlib | Framework | std library | Validator-controlled | TRUSTED | Framework upgrade by validators |
| 3 | {third_party} | Git source | {url} | YES (rev={hash}) / NO (branch) | MUST_AUDIT | {describe} |
| 4 | {on_chain_dep} | Published | {on-chain address} | YES (version pinned) / NO | MUST_AUDIT | {describe} |
| 5 | {protocol_own} | Local path | {path} | N/A (in scope) | IN_SCOPE | N/A |
Trust classification:
- TRUSTED: Sui framework packages (
sui,std). Audited by Mysten Labs, upgraded by validator governance. Minimal audit needed (but check for version-specific quirks). - MUST_AUDIT: Third-party packages. MUST analyze critical functions used by the protocol.
- IN_SCOPE: Protocol's own packages. Full audit in main analysis.
Step 2: Package Immutability Check
For each third-party dependency, assess immutability and upgrade risk:
| Dependency | Pinned to Specific Rev? | Published On-Chain? | UpgradeCap Status | Upgrade Policy | Risk |
|---|---|---|---|---|---|
| {dep} | YES (rev: {hash}) / NO (branch: main) | YES/NO | Destroyed (immutable) / Held by {who} / UNKNOWN | {compatible/additive/dep_only/immutable} | {assess} |
Source dependencies (compiled together):
- Pinned to specific git revision -> code is fixed at that commit. Safe from upstream changes.
- Pinned to a branch (e.g.,
main) -> upstream pushes automatically affect next compilation. FINDING: unpinned dependency. - No
revfield -> defaults to latest on default branch. Highest risk.
Published on-chain dependencies (referenced via published-at):
- Immutable package (UpgradeCap destroyed) -> behavior cannot change. Safe.
- Package with active UpgradeCap +
compatiblepolicy -> behavior CAN change. - Your package pins to a specific version at compile time. If dependency publishes V2, you still use V1.
- Risk: When YOU upgrade (recompile), you may pull in dependency's latest version unknowingly.
Known upgrade history: Has the dependency been upgraded before? How many versions exist? Frequent upgrades indicate active development but also active change risk.
Checklist:
- Every third-party dependency is pinned to a specific git revision (not a branch)
- Published dependencies are either immutable or their upgrade policy is documented
- No dependency uses a
latestormainbranch reference
Step 3: Transitive Dependency Risk
Map the full dependency tree:
| Dependency A | Depends On | Dep B Audited? | Dep B Upgrade Risk | Version Conflict? |
|---|---|---|---|---|
| {dep_A} | {dep_B, dep_C} | YES/NO | {describe} | YES/NO |
Transitive dependency risks:
- A -> B -> C: If C has vulnerability, A is affected even though A does not directly import C
- Version conflicts: If A depends on C v1 and B depends on C v2, Move compilation may fail. Sui resolves diamond dependencies by requiring all paths to agree on the same version.
- Transitive upgrade: If B upgrades and changes its dependency on C, your next recompile may pull different C code.
If Dep B upgrades, does it affect us through Dep A?
- Only if we recompile our package (Sui does not dynamically resolve dependencies)
- But: if Dep B is an on-chain published package that Dep A calls via CPI-equivalent, behavior changes immediately after Dep B upgrades
Step 4: Math Library Audit (CRITICAL -- Cetus Precedent)
Historical context: A major DeFi exploit targeted a bug in a custom bit shift helper function in a math library. This step is MANDATORY for any custom math/arithmetic library in the dependency tree.
For any custom math/arithmetic library dependency:
4a. Bit Shift Operation Audit (MR2)
Trace ALL bit shift operations (<<, >>) in the math library:
| # | Function | Shift Operation | Shift Amount Source | Bounds Checked? | Overflow Possible? |
|---|---|---|---|---|---|
| 1 | {func} | value << amount |
{parameter / constant / computed} | YES/NO | YES/NO |
Move bit shift rules:
<<and>>do NOT abort if shift amount >= bit width -- they produce 0- Custom bit shift helpers MUST validate shift amount < bit width
- If shift amount comes from user input or computation, it must be bounds-checked
Specific checks:
- Are ALL shift amounts validated to be < bit width of the operand type?
- Do custom bit shift helpers correctly handle edge cases (shift amount >= bit width, zero inputs, overflow)?
- Can intermediate computation produce a shift amount >= bit width?
- Are there any bit manipulation patterns that assume shift produces a specific non-zero result?
4b. Overflow/Underflow Audit
| # | Function | Operation | Input Range | Overflow Possible? | Handling |
|---|---|---|---|---|---|
| 1 | {func} | a * b |
{describe} | YES if a,b > sqrt(MAX_U128) | abort (safe) / wrapping (DANGEROUS) |
Move arithmetic safety:
- Default
+,-,*abort on overflow/underflow -- safe - But: custom math libraries may use bitwise operations to implement unchecked arithmetic for gas optimization
ascasts between integer types abort on overflow (e.g.,(x as u64)where x > MAX_U64)- Fixed-point:
(a * b) / SCALE-- intermediatea * bmay overflow u128 even if final result fits in u64
4c. Rounding and Precision
| # | Function | Rounding Direction | Consistent? | Impact if Wrong Direction |
|---|---|---|---|---|
| 1 | {mul_div} | {up / down / nearest / truncation} | YES/NO | {describe: e.g., attacker extracts extra dust per operation} |
Check: For every division operation in the math library:
- Is rounding direction documented?
- Is rounding direction consistent with how the protocol uses the result?
- Can rounding errors accumulate across many operations?
Step 5: Shared Object Dependencies
If the protocol uses shared objects from external packages:
| External Shared Object | Package | Our Functions That Access It | What We Read/Write | Behavior Change If Package Upgrades? |
|---|---|---|---|---|
| {oracle_obj} | {oracle_pkg} | {our_module::read_price} | READ price field | YES -- oracle upgrade could change price format |
| {dex_pool} | {dex_pkg} | {our_module::swap} | WRITE (swap) | YES -- DEX upgrade could change swap logic |
Are we validating shared object state after external calls?
- After reading price from external oracle shared object: do we validate freshness? bounds? format?
- After calling external DEX swap: do we validate received amount? slippage?
- If external package upgrades and changes shared object behavior, our code reads different data without any change on our side.
Key risk: External package with compatible upgrade policy can change function implementations. Our calls to those functions produce different results after upgrade, with no code change or compilation on our side.
Step 6: Interface Compatibility
Could new abort conditions be added in dependency upgrades?
| Dependency Function | Current Abort Conditions | Possible New Abort Conditions | Impact on Our Protocol |
|---|---|---|---|
| {dep::func} | {list current aborts} | {what upgrades could add} | {describe: e.g., our transaction aborts unexpectedly} |
Check:
- If a dependency function currently never aborts but an upgrade adds an abort condition -> our protocol's transactions may start failing
- If a dependency function changes its return value semantics (e.g., rounding direction changes) -> our calculations become incorrect
- If a dependency adds new type constraints -> our generic calls may no longer compile on next recompile
Key Questions (Must Answer All)
- Pinning: Are all third-party dependencies pinned to specific git revisions?
- Critical functions: For each math/utility function from a dependency, does it handle edge cases correctly?
- Bit shifts: Are ALL bit shift operations in math libraries bounds-checked? (Cetus precedent)
- Upgrade risk: Can any dependency change behavior without the protocol team's knowledge?
- Shared objects: If we use shared objects from external packages, can their behavior change via upgrade?
- Transitive: Are there transitive dependencies, and are they audited?
Common False Positives
- Framework dependencies:
sui::*andstd::*are validator-controlled and well-audited. Findings about framework functions are rarely valid unless version-specific. - Pinned and immutable: Dependency pinned to specific rev AND on-chain package is immutable -> no upgrade risk.
- Unused imports: Dependency imported but no functions actually called -> no runtime risk.
- Well-known libraries: Widely-used and audited libraries with specific rev pinning -> lower risk, but STILL check edge cases for specific functions used.
Output Schema
## Finding [DEP-N]: Title
**Verdict**: CONFIRMED / PARTIAL / REFUTED / CONTESTED
**Step Execution**: check1,2,3,4,5,6 | skip(reason) | uncertain
**Rules Applied**: [R1:___, R4:___, R8:___, R10:___]
**Severity**: Critical/High/Medium/Low/Info
**Location**: Move.toml or sources/{module}.move:LineN (where dep function is called)
**Dependency**: {dependency_name}
**Function**: {specific function if applicable}
**Issue Type**: UNPINNED_VERSION / ARITHMETIC_UNSAFE / BIT_SHIFT_UNSAFE / EDGE_CASE_UNHANDLED / SPEC_MISMATCH / TRANSITIVE_RISK / UPGRADE_RISK / SHARED_OBJECT_DEP
**Description**: What is wrong
**Impact**: What can happen (incorrect calculation, overflow, unexpected abort, supply manipulation)
**Evidence**: Code showing the issue
**Recommendation**: How to fix (pin version, add validation, use alternative, wrap with checks)
Step Execution Checklist (MANDATORY)
| Step | Required | Completed? | Notes |
|---|---|---|---|
| 1. Dependency Inventory | YES | All deps from Move.toml enumerated | |
| 2. Package Immutability Check | YES | Pinning and on-chain policy for each dep | |
| 3. Transitive Dependency Risk | YES | Full dependency tree mapped | |
| 4. Math Library Audit | IF math/arithmetic deps exist | HIGH PRIORITY -- Cetus precedent | |
| 4a. Bit Shift Operation Audit | IF bit shifts in math deps | Every shift bounds-checked | |
| 4b. Overflow/Underflow Audit | IF math deps | Checked vs unchecked arithmetic | |
| 4c. Rounding and Precision | IF division in math deps | Direction documented and consistent | |
| 5. Shared Object Dependencies | IF external shared objects used | Behavior change on upgrade | |
| 6. Interface Compatibility | IF upgradeable deps | New abort conditions, return value changes |
Cross-Reference Markers
After Step 2: If any dependency unpinned -> immediate Informational/Low finding.
After Step 4: If math library has unchecked bit shifts -> cross-reference with BIT_SHIFT_SAFETY skill for protocol-level impact analysis.
After Step 5: If shared object dependencies from upgradeable packages -> cross-reference with PACKAGE_VERSION_SAFETY Step 3 and EXTERNAL_PRECONDITION_AUDIT Step 3b.
If any step skipped, document valid reason (N/A, no third-party deps, framework-only, no math functions used).
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?