Back to skill

Security audit

Web3 & Blockchain Engineering

Security checks for vulnerabilities and agentic risk

Overview

This skill is transparent and does not install code, but a security-focused blockchain skill includes a flawed vault example that could mislead users into unsafe financial code.

Review this skill carefully before using it to generate or copy production smart contracts. Treat its checklists as educational, but do not reuse the VaultV1 example without fixing the accounting issues and having qualified smart contract security review.

Vulnerability Patterns
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:156
Finding

Unsafe Vault Accounting Can Corrupt Share and Asset Balances

Content
View full analysis

Vulnerability Details

File Location: SKILL.md, lines 156-170
Vulnerability Type: Unsafe integer downcasting and incorrect token receipt accounting
Risk Level: Medium

Vulnerable Code

solidity
mintedShares = totalDeposits == 0
    ? amount
    : (amount * totalShares) / totalDeposits;

// Effects before interactions (CEI pattern)
totalDeposits += uint128(amount);
totalShares += uint128(mintedShares);
shares[msg.sender] += mintedShares;

// Interaction last
asset.safeTransferFrom(msg.sender, address(this), amount);

Technical Analysis

The reference vault performs explicit conversions from uint256 to uint128 without verifying that amount and mintedShares fit within 128 bits. Explicit narrowing conversions can truncate high-order bits rather than safely rejecting an out-of-range value. Consequently, the user's full uint256 share balance can diverge from the truncated global accounting values.

For example, during the first deposit, mintedShares equals amount. If that amount exceeds type(uint128).max, shares[msg.sender] records the full value while totalDeposits and totalShares receive narrowed values. Future share calculations then operate on corrupted global totals.

The implementation also assumes that safeTransferFrom delivers exactly amount tokens. Fee-on-transfer, deflationary, or otherwise non-standard tokens can transfer fewer tokens than requested. The vault nevertheless credits the requested amount, causing its recorded assets and issued shares to exceed its actual token balance.

The associated fuzz test restricts deposits to uint128 values and uses a conventional mock ERC-20 token. It therefore does not exercise oversized deposits or fee-on-transfer behavior.

Attack Path

Oversized-deposit path:

  1. A vault is deployed using the documented reference implementation.
  2. The configured token permits a deposit whose raw token amount exceeds ` ...[truncated 1624 chars]
Remediation
View remediation

Remediation Suggestions

  1. Use uint256 for totalDeposits and totalShares unless storage packing is demonstrably necessary.

  2. If uint128 storage is required, use checked conversions that revert when values exceed type(uint128).max, such as OpenZeppelin SafeCast.toUint128.

  3. Measure the actual amount received using token balance differences:

    solidity
    uint256 balanceBefore = asset.balanceOf(address(this));
    asset.safeTransferFrom(msg.sender, address(this), amount);
    uint256 received = asset.balanceOf(address(this)) - balanceBefore;
    
  4. Calculate and issue shares from received, not from the caller-supplied amount.

  5. Alternatively, explicitly reject fee-on-transfer and rebasing tokens and document that restriction as an enforced invariant.

  6. Revert when a nonzero deposit would mint zero shares.

  7. Ensure all global totals, individual balances, and actual token balances remain consistent through invariant tests.

  8. Add tests for:

    • type(uint128).max and values above that boundary.
    • Fee-on-transfer and deflationary tokens.
    • Tokens with unusual decimal configurations.
    • Rounding behavior for small deposits.
    • The invariant that actual assets are at least recorded liabilities.
    • Full deposit and withdrawal sequences under fuzzing.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (2)

Ae4

Medium
Category
analysis-evasion
Confidence
80% confidence
Finding

Suspicious Unicode normalization or mixed-script content

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
75% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

Scanner excerpt · SKILL.md (reported line 301)May include surrounding context.

md
4. **Oracle freshness** — Price data is within acceptable staleness window
5. **Liquidation viability** — Undercollateralized positions can always be liquidated
6. **Access control** — Admin functions behind timelock + multisig
7. **Withdrawal guarantee** — Users can always withdraw their assets (no lock-up without consent)

---

Static analysis

No suspicious patterns detected.