.claude/skills/building-secure-contracts/SKILL.md
Smart contract and secure API contract security analysis — invariant checking, access control, reentrancy, and integer overflow patterns. Implements Checks-Effects-Interactions pattern, formal invariant verification, and OpenSCV vulnerability taxonomy for Solidity/EVM and Rust/Solana contracts.
npx skillsauth add oimiragieo/agent-studio building-secure-contractsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This skill applies systematic security analysis to smart contracts and secure API contracts. The core principle: every state mutation must be proven safe through invariant verification before an external call executes. It covers both EVM (Solidity) and Solana (Rust) ecosystems with platform-specific vulnerability patterns.
Vulnerability taxonomy: OpenSCV (94 classified security issues) Critical patterns: CEI, reentrancy guards, access modifiers, SafeMath equivalents Risk landscape: $1.8B+ in DeFi exploits Q3 2025 (access control: $953M, reentrancy: $420M)
onlyOwner, onlyRole, and custom guard.Goal: Map the attack surface before deep analysis.
call(), transfer(), ERC20 hooks, interface calls## Contract Reconnaissance
### Entry Points
- [ ] `withdraw(uint256 amount)` — external, state-mutating, calls msg.sender
- [ ] `deposit()` — payable, updates balances mapping
### Access Control Map
- [ ] `onlyOwner`: [list of functions]
- [ ] `onlyRole(ADMIN_ROLE)`: [list of functions]
- [ ] No modifier (verify intent): [list of functions]
### External Calls
- [ ] `msg.sender.call{value: amount}("")` at withdraw():L45
- [ ] `token.transferFrom(...)` at deposit():L23
### Trust Boundaries
- [ ] User-supplied amount at withdraw():L40
- [ ] Oracle price feed at getPrice():L67 — manipulation risk
Goal: Identify all reentrancy vectors (direct, cross-function, read-only).
For each function with external calls:
### Function: withdraw(uint256 amount)
#### CEI Order Analysis
- L40: CHECK — require(balances[msg.sender] >= amount) ✓
- L45: EXTERNAL CALL — msg.sender.call{value: amount}("") ← VIOLATION
- L48: EFFECT — balances[msg.sender] -= amount ← STATE AFTER CALL
**FINDING**: Classic reentrancy — balance updated after external call.
**Fix**: Move L48 before L45 (CEI pattern)
**Severity**: Critical
#### Fixed Pattern
```solidity
require(balances[msg.sender] >= amount);
balances[msg.sender] -= amount; // Effect BEFORE external call
(bool success, ) = msg.sender.call{value: amount}("");
require(success);
```
Identify shared state between functions that both make external calls:
### Shared State: balances mapping
- withdraw() reads + writes balances + makes external call
- emergencyWithdraw() reads + writes balances + makes external call
**RISK**: Reentrancy from withdraw() into emergencyWithdraw() bypasses checks
Goal: Verify every state-mutating function has appropriate guards.
For each function:
### Function Audit: updateTreasury(address newTreasury)
- [ ] Has access modifier? → NO ← FINDING: Missing onlyOwner
- [ ] Modifier verified in contract? → N/A (not present)
- [ ] Owner transferable safely? → N/A
- [ ] Time lock for critical changes? → NO
**Severity**: Critical — anyone can redirect protocol treasury
**Fix**: Add `onlyOwner` modifier and time-lock for parameter changes
### Role Check: PAUSER_ROLE vs ADMIN_ROLE
- pause() requires: PAUSER_ROLE
- unpause() requires: PAUSER_ROLE (RISK: pauser can also unpause)
- grantRole() requires: ADMIN_ROLE
**Issue**: Pauser can unilaterally pause and unpause — should require separate roles
**Severity**: Medium
Goal: Identify overflow, underflow, precision loss, and rounding direction bugs.
### Function: calculateReward(uint256 principal, uint256 rate)
- L88: `uint256 reward = principal * rate / 1e18`
- Multiplication before division: OK (avoids precision loss)
- Overflow check: principal \* rate could overflow if both > sqrt(uint256.max)
- Rounding: truncates toward zero — check if favors protocol or user
- `unchecked` block? → NO → Solidity 0.8+ protects this
### Unchecked Block Analysis
- L102-108: `unchecked { ... }`
- Why unchecked? Check comment and verify mathematician's claim
- Is the claimed impossibility of overflow actually proven?
- [UNVERIFIED] claim: "amount < balance guarantees no underflow"
Goal: Identify and verify all contract-level invariants.
### Contract Invariants: LiquidityPool
1. **Solvency**: sum(balances) == address(this).balance — [VERIFIED L90]
2. **Total supply**: totalSupply == sum(all user shares) — [UNVERIFIED]
3. **Fee bound**: fee <= MAX_FEE (1000 bps) — [VERIFIED by require at L45]
4. **Non-zero denominator**: totalSupply > 0 before share calculation — [VIOLATED at L67, division-by-zero risk on first deposit]
### Invariant Violation Findings
**FINDING**: Invariant 4 violated — first depositor can cause division by zero
- Location: L67 `shares = amount * totalSupply / totalAssets`
- When: totalSupply == 0 on first deposit
- Impact: DoS attack on first deposit; protocol initialization blocked
- Fix: Handle zero totalSupply case separately with initial share ratio
# Security Report: [Contract Name]
## Summary
- Functions analyzed: N
- Findings: N (Critical: X, High: Y, Medium: Z, Low: W)
- Invariants verified: N of M
- CEI violations: N
## Critical Findings
### [F-01] Reentrancy in withdraw()
- Location: `src/Pool.sol:L45`
- Pattern: External call before state update (CEI violation)
- Impact: Complete fund drainage
- Fix: Apply CEI pattern — update state before external call
- 5 Whys: [root cause chain]
## Invariant Status
| Invariant | Status | Evidence |
| -------------------------- | ---------- | ------------------- |
| sum(balances) == balance | VERIFIED | L90 invariant check |
| totalSupply == sum(shares) | UNVERIFIED | No test coverage |
## Recommendations
1. [Critical] Fix reentrancy in withdraw() before deployment
2. [High] Add reentrancy guard as defense-in-depth
3. [Medium] Add formal invariant tests via Foundry invariant suite
audit-context-building for initial code reconnaissancebuilding-secure-contracts for contract-specific analysissecurity-architect for threat modelingstatic-analysis (Semgrep/CodeQL) for automated confirmationmedusa-security for fuzzing-based invariant testing| Skill | Relationship |
| ------------------------ | ---------------------------------------------------- |
| audit-context-building | Builds initial mental model before contract analysis |
| security-architect | Consumes findings for threat modeling and STRIDE |
| static-analysis | Automated SAST confirmation of manual findings |
| medusa-security | Fuzzing and property-based testing for invariants |
| variant-analysis | Finds similar vulnerability patterns across codebase |
| web3-expert | Solidity/Ethereum ecosystem expertise |
| Anti-Pattern | Why It Fails | Correct Approach |
| ----------------------------------------------- | -------------------------------------------------------------- | ----------------------------------------------------------- |
| Auditing only the happy path | Reentrancy and access control bugs are invisible in happy path | Explicitly trace every error path and external call |
| Trusting function name for access control | onlyAdmin() might not check the actual admin role | Read the modifier implementation, not just its name |
| Assuming Solidity 0.8 prevents all integer bugs | unchecked blocks, assembly, and casting bypass protection | Audit all unchecked blocks and type casts explicitly |
| Skipping cross-function reentrancy | Cross-function reentrancy bypasses single-function guards | Map shared state across ALL functions making external calls |
| Leaving invariants implicit | Unwritten invariants are unverified risks | Document every invariant in NatSpec before analysis |
Before starting: Check .claude/context/memory/learnings.md for prior contract audits of the same protocol or token standard.
During analysis: Write incremental findings to context report as discovered. Do not wait until the end.
After completion: Record key findings and patterns to .claude/context/memory/learnings.md. Record architecture decisions (CEI enforcement patterns, invariant frameworks) to decisions.md.
tools
Comprehensive biosignal processing toolkit for analyzing physiological data including ECG, EEG, EDA, RSP, PPG, EMG, and EOG signals. Use this skill when processing cardiovascular signals, brain activity, electrodermal responses, respiratory patterns, muscle activity, or eye movements. Applicable for heart rate variability analysis, event-related potentials, complexity measures, autonomic nervous system assessment, psychophysiology research, and multi-modal physiological signal integration.
tools
Comprehensive toolkit for creating, analyzing, and visualizing complex networks and graphs in Python. Use when working with network/graph data structures, analyzing relationships between entities, computing graph algorithms (shortest paths, centrality, clustering), detecting communities, generating synthetic networks, or visualizing network topologies. Applicable to social networks, biological networks, transportation systems, citation networks, and any domain involving pairwise relationships.
data-ai
Molecular featurization for ML (100+ featurizers). ECFP, MACCS, descriptors, pretrained models (ChemBERTa), convert SMILES to features, for QSAR and molecular ML.
development
Run Python code in the cloud with serverless containers, GPUs, and autoscaling. Use when deploying ML models, running batch processing jobs, scheduling compute-intensive tasks, or serving APIs that require GPU acceleration or dynamic scaling.