From atum-stack-backend
Smart contract security audit pattern library — SWC Registry vulnerabilities (reentrancy SWC-107, integer overflow SWC-101, access control SWC-115, unchecked call return SWC-104, denial of service SWC-113, weak randomness SWC-120, front-running SWC-114, timestamp dependence SWC-116, signature replay SWC-121), formal analysis tools (Slither static analyzer, Mythril symbolic execution, Certora Prover formal verification, Echidna property-based fuzzer, Manticore), MEV mitigation (commit-reveal schemes, batch auctions, private mempools Flashbots Protect), economic attack vectors (oracle manipulation via flash loans, sandwich attacks, JIT liquidity), upgrade safety (storage collisions, function selector clashes in proxies), and the pre-audit checklist (CEI pattern verification, reentrancy guards on every external interaction, custom errors review, access control matrix, integer arithmetic safety, gas griefing). Use when auditing existing contracts before mainnet deploy, hardening DeFi protocols, integrating Slither/Mythril into CI, or designing security-first contract architectures. Differentiates from generic security-reviewer by EVM-specific attack vectors (reentrancy, MEV, oracle manipulation, flash loan attacks) that don't exist in traditional web apps.
npx claudepluginhub arnwaldn/atum-plugins-collection --plugin atum-stack-backendThis skill uses the workspace's default tool permissions.
Ce skill couvre les **vulnérabilités spécifiques aux smart contracts EVM** et les outils pour les détecter. Aucune autre catégorie de bug ne se traduit aussi rapidement en perte irrécupérable de fonds.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Guides implementation of event-driven hooks in Claude Code plugins using prompt-based validation and bash commands for PreToolUse, Stop, and session events.
Ce skill couvre les vulnérabilités spécifiques aux smart contracts EVM et les outils pour les détecter. Aucune autre catégorie de bug ne se traduit aussi rapidement en perte irrécupérable de fonds.
Règle de base : un smart contract déployé en mainnet est immuable (sauf upgrade). Audit AVANT, pas après.
L'attaque fondatrice (The DAO 2016 → ETH/ETC fork). Une fonction qui appelle un contrat externe AVANT d'updater son state peut être ré-entrée par le callee.
// VULNERABLE
function withdraw() external {
uint256 amount = balances[msg.sender];
(bool ok, ) = msg.sender.call{value: amount}(""); // ← attaquant peut ré-entrer ici
require(ok);
balances[msg.sender] = 0; // Trop tard
}
// SAFE: CEI + ReentrancyGuard
function withdraw() external nonReentrant {
uint256 amount = balances[msg.sender];
balances[msg.sender] = 0; // Effects AVANT
(bool ok, ) = msg.sender.call{value: amount}(""); // Interaction APRÈS
require(ok);
}
// VULNERABLE — phishing
modifier onlyOwner() {
require(tx.origin == owner);
_;
}
// SAFE
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
// VULNERABLE — silent failure
recipient.call{value: amount}("");
// SAFE
(bool ok, ) = recipient.call{value: amount}("");
require(ok, "Transfer failed");
Le mempool est public. Une transaction avec une commission élevée peut passer devant. Exemple : un MEV bot voit un swap qui va déplacer le prix → il achète avant et vend après (sandwich).
Mitigations :
minOut paramètre dans les swaps// VULNERABLE
function lottery() external {
if (block.timestamp % 2 == 0) {
// payout
}
}
Les miners peuvent ajuster block.timestamp de quelques secondes. Pour de l'aléatoire vrai → Chainlink VRF.
// VULNERABLE
function permit(address user, uint256 amount, bytes calldata signature) external {
bytes32 hash = keccak256(abi.encodePacked(user, amount));
address signer = recover(hash, signature);
require(signer == user);
_doSomething(amount); // Peut être rejoué !
}
// SAFE: nonce + chain ID + contract address (EIP-712)
function permit(address user, uint256 amount, uint256 nonce, bytes calldata signature) external {
require(nonce == nonces[user]++, "Invalid nonce");
bytes32 domain = keccak256(abi.encode(EIP712_DOMAIN, address(this), block.chainid));
bytes32 hash = keccak256(abi.encodePacked("\x19\x01", domain, keccak256(abi.encode(user, amount, nonce))));
require(recover(hash, signature) == user);
_doSomething(amount);
}
pip install slither-analyzer
slither . --filter-paths "lib|test"
Sortie type : detection de reentrancy, integer overflow, uninitialized state, missing zero address checks, etc.
# .github/workflows/security.yml
- name: Slither
uses: crytic/slither-action@v0.3
with:
target: 'src/'
fail-on: medium
pip install mythril
myth analyze src/MyContract.sol --solv 0.8.26
Plus lourd que Slither, plus profond. Bon pour les audits ponctuels.
// echidna_test.sol
contract Test is MyToken {
function echidna_total_supply_never_exceeds_max() public view returns (bool) {
return totalSupply() <= maxSupply;
}
function echidna_balance_sum_equals_total_supply() public view returns (bool) {
// ...
return true;
}
}
echidna . --contract Test --test-mode property
Spec en CVL (Certora Verification Language) qui prouve mathematiquement des propriétés.
mapping(address => bytes32) public commitments;
mapping(address => uint256) public commitBlock;
function commit(bytes32 hash) external {
commitments[msg.sender] = hash;
commitBlock[msg.sender] = block.number;
}
function reveal(uint256 value, bytes32 salt) external {
require(block.number > commitBlock[msg.sender] + 5, "Wait 5 blocks");
require(keccak256(abi.encodePacked(value, salt, msg.sender)) == commitments[msg.sender], "Invalid");
// ... process value ...
}
function swap(uint256 amountIn, uint256 minAmountOut, address tokenOut) external {
uint256 amountOut = _calcSwap(amountIn, tokenOut);
require(amountOut >= minAmountOut, "Slippage too high");
// ... execute ...
}
Le user envoie sa tx via le RPC https://rpc.flashbots.net/ au lieu du mempool public. La tx est forwarded directement aux validators sans passer par le mempool → MEV bots ne peuvent pas la voir.
// VULNERABLE: prix d'oracle = balance de DEX
function priceOf(address token) public view returns (uint256) {
return ERC20(token).balanceOf(uniswapPair) * 1e18 / ERC20(WETH).balanceOf(uniswapPair);
}
Un attaquant flash-loan 1M$, swap dans Uniswap → fait varier le prix → liquide des positions au prix manipulé → remboursement du flash-loan dans le même block.
Mitigations :
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
contract MyContract is AccessControl {
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
constructor(address admin) {
_grantRole(DEFAULT_ADMIN_ROLE, admin);
}
function mint(address to, uint256 amount) external onlyRole(MINTER_ROLE) {
// ...
}
}
import {TimelockController} from "@openzeppelin/contracts/governance/TimelockController.sol";
// Constructor d'un contrat important :
// _grantRole(DEFAULT_ADMIN_ROLE, address(timelock));
// _grantRole(DEFAULT_ADMIN_ROLE, address(0)); // Renounce direct admin
Toute action admin doit passer par un multisig (Gnosis Safe 3-of-5 par exemple) qui propose la tx au Timelock, et le timelock applique après 48h. Les users ont 48h pour réagir si le multisig est compromis.
// V1
contract MyContractV1 {
uint256 public a; // slot 0
uint256 public b; // slot 1
}
// V2 — BAD
contract MyContractV2 {
uint256 public b; // slot 0 ← collision, b lit la valeur de a
uint256 public a; // slot 1
}
// V2 — GOOD
contract MyContractV2 {
uint256 public a; // slot 0
uint256 public b; // slot 1
uint256 public c; // slot 2 (nouveau)
}
OpenZeppelin Upgrades plugin détecte ces collisions automatiquement.
Le proxy a une fonction admin() qui peut entrer en collision avec une fonction du contrat implémentation. Solutions :
^0.8.0 → fixer la version exactementexternal/public ont nonReentrant quand appropriétx.origin jamais utiliséblock.timestamp / blockhash jamais comme source d'aléa# .github/workflows/security.yml
name: Security
on: [pull_request, push]
jobs:
slither:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: crytic/slither-action@v0.3
with:
target: 'src/'
fail-on: medium
mythril:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: pip install mythril
- run: myth analyze src/*.sol --solv 0.8.26 --execution-timeout 120
echidna:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: crytic/echidna-action@v2
with:
files: .
contract: TestContract
test-mode: assertion
solidity-patterns (ce plugin)web3-integration (ce plugin)blockchain-expert (ce plugin)