solidity-security
Master smart contract security best practices to prevent common vulnerabilities and implement secure Solidity patterns. Use when writing smart contracts, auditing existing contracts, or implementing security measures for blockchain applications.
What this skill does
# Solidity Security
Master smart contract security best practices, vulnerability prevention, and secure Solidity development patterns.
## When to Use This Skill
- Writing secure smart contracts
- Auditing existing contracts for vulnerabilities
- Implementing secure DeFi protocols
- Preventing reentrancy, overflow, and access control issues
- Optimizing gas usage while maintaining security
- Preparing contracts for professional audits
- Understanding common attack vectors
## Critical Vulnerabilities
### 1. Reentrancy
Attacker calls back into your contract before state is updated.
**Vulnerable Code:**
```solidity
// VULNERABLE TO REENTRANCY
contract VulnerableBank {
mapping(address => uint256) public balances;
function withdraw() public {
uint256 amount = balances[msg.sender];
// DANGER: External call before state update
(bool success, ) = msg.sender.call{value: amount}("");
require(success);
balances[msg.sender] = 0; // Too late!
}
}
```
**Secure Pattern (Checks-Effects-Interactions):**
```solidity
contract SecureBank {
mapping(address => uint256) public balances;
function withdraw() public {
uint256 amount = balances[msg.sender];
require(amount > 0, "Insufficient balance");
// EFFECTS: Update state BEFORE external call
balances[msg.sender] = 0;
// INTERACTIONS: External call last
(bool success, ) = msg.sender.call{value: amount}("");
require(success, "Transfer failed");
}
}
```
**Alternative: ReentrancyGuard**
```solidity
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
contract SecureBank is ReentrancyGuard {
mapping(address => uint256) public balances;
function withdraw() public nonReentrant {
uint256 amount = balances[msg.sender];
require(amount > 0, "Insufficient balance");
balances[msg.sender] = 0;
(bool success, ) = msg.sender.call{value: amount}("");
require(success, "Transfer failed");
}
}
```
### 2. Integer Overflow/Underflow
**Vulnerable Code (Solidity < 0.8.0):**
```solidity
// VULNERABLE
contract VulnerableToken {
mapping(address => uint256) public balances;
function transfer(address to, uint256 amount) public {
// No overflow check - can wrap around
balances[msg.sender] -= amount; // Can underflow!
balances[to] += amount; // Can overflow!
}
}
```
**Secure Pattern (Solidity >= 0.8.0):**
```solidity
// Solidity 0.8+ has built-in overflow/underflow checks
contract SecureToken {
mapping(address => uint256) public balances;
function transfer(address to, uint256 amount) public {
// Automatically reverts on overflow/underflow
balances[msg.sender] -= amount;
balances[to] += amount;
}
}
```
**For Solidity < 0.8.0, use SafeMath:**
```solidity
import "@openzeppelin/contracts/utils/math/SafeMath.sol";
contract SecureToken {
using SafeMath for uint256;
mapping(address => uint256) public balances;
function transfer(address to, uint256 amount) public {
balances[msg.sender] = balances[msg.sender].sub(amount);
balances[to] = balances[to].add(amount);
}
}
```
### 3. Access Control
**Vulnerable Code:**
```solidity
// VULNERABLE: Anyone can call critical functions
contract VulnerableContract {
address public owner;
function withdraw(uint256 amount) public {
// No access control!
payable(msg.sender).transfer(amount);
}
}
```
**Secure Pattern:**
```solidity
import "@openzeppelin/contracts/access/Ownable.sol";
contract SecureContract is Ownable {
function withdraw(uint256 amount) public onlyOwner {
payable(owner()).transfer(amount);
}
}
// Or implement custom role-based access
contract RoleBasedContract {
mapping(address => bool) public admins;
modifier onlyAdmin() {
require(admins[msg.sender], "Not an admin");
_;
}
function criticalFunction() public onlyAdmin {
// Protected function
}
}
```
### 4. Front-Running
**Vulnerable:**
```solidity
// VULNERABLE TO FRONT-RUNNING
contract VulnerableDEX {
function swap(uint256 amount, uint256 minOutput) public {
// Attacker sees this in mempool and front-runs
uint256 output = calculateOutput(amount);
require(output >= minOutput, "Slippage too high");
// Perform swap
}
}
```
**Mitigation:**
```solidity
contract SecureDEX {
mapping(bytes32 => bool) public usedCommitments;
// Step 1: Commit to trade
function commitTrade(bytes32 commitment) public {
usedCommitments[commitment] = true;
}
// Step 2: Reveal trade (next block)
function revealTrade(
uint256 amount,
uint256 minOutput,
bytes32 secret
) public {
bytes32 commitment = keccak256(abi.encodePacked(
msg.sender, amount, minOutput, secret
));
require(usedCommitments[commitment], "Invalid commitment");
// Perform swap
}
}
```
## Security Best Practices
### Checks-Effects-Interactions Pattern
```solidity
contract SecurePattern {
mapping(address => uint256) public balances;
function withdraw(uint256 amount) public {
// 1. CHECKS: Validate conditions
require(amount <= balances[msg.sender], "Insufficient balance");
require(amount > 0, "Amount must be positive");
// 2. EFFECTS: Update state
balances[msg.sender] -= amount;
// 3. INTERACTIONS: External calls last
(bool success, ) = msg.sender.call{value: amount}("");
require(success, "Transfer failed");
}
}
```
### Pull Over Push Pattern
```solidity
// Prefer this (pull)
contract SecurePayment {
mapping(address => uint256) public pendingWithdrawals;
function recordPayment(address recipient, uint256 amount) internal {
pendingWithdrawals[recipient] += amount;
}
function withdraw() public {
uint256 amount = pendingWithdrawals[msg.sender];
require(amount > 0, "Nothing to withdraw");
pendingWithdrawals[msg.sender] = 0;
payable(msg.sender).transfer(amount);
}
}
// Over this (push)
contract RiskyPayment {
function distributePayments(address[] memory recipients, uint256[] memory amounts) public {
for (uint i = 0; i < recipients.length; i++) {
// If any transfer fails, entire batch fails
payable(recipients[i]).transfer(amounts[i]);
}
}
}
```
### Input Validation
```solidity
contract SecureContract {
function transfer(address to, uint256 amount) public {
// Validate inputs
require(to != address(0), "Invalid recipient");
require(to != address(this), "Cannot send to contract");
require(amount > 0, "Amount must be positive");
require(amount <= balances[msg.sender], "Insufficient balance");
// Proceed with transfer
balances[msg.sender] -= amount;
balances[to] += amount;
}
}
```
### Emergency Stop (Circuit Breaker)
```solidity
import "@openzeppelin/contracts/security/Pausable.sol";
contract EmergencyStop is Pausable, Ownable {
function criticalFunction() public whenNotPaused {
// Function logic
}
function emergencyStop() public onlyOwner {
_pause();
}
function resume() public onlyOwner {
_unpause();
}
}
```
## Gas Optimization
### Use `uint256` Instead of Smaller Types
```solidity
// More gas efficient
contract GasEfficient {
uint256 public value; // Optimal
function set(uint256 _value) public {
value = _value;
}
}
// Less efficient
contract GasInefficient {
uint8 public value; // Still uses 256-bit slot
function set(uint8 _value) public {
value = _value; // Extra gas for type conversion
}
}
```
### Pack Storage Variables
```solidity
// Gas efficient (3 variables in 1 slot)
contract PackedStorage {
Related in Security
mac-ops
IncludedComprehensive macOS workstation operations — diagnose kernel panics, identify failing drives, audit launchd startup items, decode wake reasons, triage TCC permission denials, manage APFS snapshots, recover from no-boot. Use for: Mac is slow, slow bootup, won't boot, kernel panic, kernel_task hot, mds_stores CPU, photoanalysisd, cloudd, login loop, gray screen, sleep wake failure, drive failing, IO errors, APFS snapshots eating space, Time Machine local snapshots, Spotlight indexing, launchd, LaunchAgent, LaunchDaemon, login items, TCC permissions, Full Disk Access, Screen Recording denied, Gatekeeper, quarantine, com.apple.quarantine, app is damaged, helper tool, /Library/PrivilegedHelperTools, pmset, wake reasons, dark wake, sysdiagnose, panic.ips, DiagnosticReports, configuration profile, MDM profile, remote diagnostics over SSH.
a11y-audit
IncludedRun accessibility audits on web projects combining automated scanning (axe-core, Lighthouse) with WCAG 2.1 AA compliance mapping, manual check guidance, and structured reporting. Output is configurable: markdown report only, markdown plus machine-readable JSON, or markdown plus issue tracker integration. Use this skill whenever the user mentions "accessibility audit", "a11y audit", "WCAG audit", "accessibility check", "compliance scan", or asks to check a web project for accessibility issues. Also trigger when the user wants to verify WCAG conformance or map findings to a specific standard (CAN-ASC-6.2, EN 301 549, ADA/AODA).
erpclaw
IncludedAI-native ERP system with self-extending OS. Full accounting, invoicing, inventory, purchasing, tax, billing, HR, payroll, advanced accounting (ASC 606/842, intercompany, consolidation), and financial reporting. 413 actions across 14 domains, 43 expansion modules. Constitutional guardrails, adversarial audit, schema migration. Double-entry GL, immutable audit trail, US GAAP.
assess
IncludedAssesses and rates quality 0-10 across multiple dimensions (correctness, maintainability, security, performance, testability, simplicity) with pros/cons analysis. Compares against project conventions and prior decisions from memory. Produces structured evaluation reports with actionable improvement suggestions. Use when evaluating code, designs, architectures, or comparing alternative approaches.
spring-boot-security-jwt
IncludedProvides JWT authentication and authorization patterns for Spring Boot 3.5.x covering token generation with JJWT, Bearer/cookie authentication, database/OAuth2 integration, and RBAC/permission-based access control using Spring Security 6.x. Use when implementing authentication or authorization in Spring Boot applications.
code-hardcode-audit
IncludedDetect hardcoded values, magic numbers, and leaked secrets. TRIGGERS - hardcode audit, magic numbers, PLR2004, secret scanning.