Slither — статический анализ контрактов
Как установить Slither, запустить статический анализ Solidity-контрактов и читать findings перед деплоем.
Что делает Slither
Slither — это статический анализатор Solidity и Vyper-контрактов. Он читает код без деплоя и ищет паттерны, которые часто приводят к уязвимостям.
Slither не заменяет аудит, но быстро ловит типовые ошибки: tx.origin, reentrancy, опасные low-level calls, неправильные modifiers, shadowing, dead code и подозрительные зависимости.
Устанавливаем и запускаем Slither
Установите Slither:
uv tool install slither-analyzerЕсли uv не используется:
pip install slither-analyzerЗапуск в Hardhat или Foundry-проекте:
slither .Запуск одного файла:
slither contracts/SlitherDemo.solВывод в JSON для CI:
slither . --json slither-results.jsonПроверяем контракт с ошибками
Создайте файл contracts/SlitherDemo.sol:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract UnsafeTreasury {
address public owner;
mapping(address => uint256) public balances;
error NotOwner();
error NothingToWithdraw();
error EthTransferFailed();
constructor() {
owner = msg.sender;
}
function deposit() external payable {
balances[msg.sender] += msg.value;
}
function withdrawAll() external {
if (tx.origin != owner) {
revert NotOwner();
}
uint256 amount = balances[msg.sender];
if (amount == 0) {
revert NothingToWithdraw();
}
(bool success,) = msg.sender.call{value: amount}("");
if (!success) {
revert EthTransferFailed();
}
balances[msg.sender] = 0;
}
}
contract SafeTreasury {
address public immutable owner;
mapping(address => uint256) public balances;
error NotOwner();
error NothingToWithdraw();
error EthTransferFailed();
constructor() {
owner = msg.sender;
}
modifier onlyOwner() {
if (msg.sender != owner) {
revert NotOwner();
}
_;
}
function deposit() external payable {
balances[msg.sender] += msg.value;
}
function withdrawAll() external onlyOwner {
uint256 amount = balances[msg.sender];
if (amount == 0) {
revert NothingToWithdraw();
}
balances[msg.sender] = 0;
(bool success,) = msg.sender.call{value: amount}("");
if (!success) {
revert EthTransferFailed();
}
}
}Запустите анализ:
slither contracts/SlitherDemo.solSlither должен подсветить опасные места в UnsafeTreasury: проверку через tx.origin и внешний call до обновления state.
Как читать findings
Finding Slither обычно отвечает на три вопроса:
Что найдено: tx.origin используется для авторизации
Где найдено: contracts/SlitherDemo.sol, withdrawAll()
Почему опасно: другой контракт может заставить owner вызвать вашу функциюСначала исправляйте high и medium findings. Low и informational тоже смотрите, но не блокируйте деплой только из-за стиля имени переменной.
Если finding ложноположительный, не игнорируйте его молча. Оставьте комментарий в PR или добавьте triage-запись, чтобы команда понимала решение.
Фильтруем и настраиваем запуск
Показать все detectors:
slither --list-detectorsЗапустить только конкретные detectors:
slither . --detect reentrancy-eth,tx-originИсключить шумные detectors:
slither . --exclude naming-convention,unused-stateНе показывать зависимости:
slither . --filter-paths "node_modules|openzeppelin"Сохранить результат для GitHub code scanning или SARIF viewer:
slither . --sarif slither-results.sarifКонфиг для проекта
Создайте файл slither.config.json:
{
"detectors_to_run": "all",
"detectors_to_exclude": "naming-convention,unused-state",
"exclude_dependencies": true,
"filter_paths": "node_modules|openzeppelin",
"json": "slither-results.json",
"sarif": null,
"triage_database": "slither.db.json",
"show_ignored_findings": false
}Запуск с конфигом:
slither . --config-file slither.config.jsonДля интерактивного скрытия известных findings используйте triage mode:
slither . --triage-modeSlither сохранит решения в slither.db.json. Этот файл полезен в команде, но его нельзя использовать как способ скрыть реальные уязвимости перед ревью.
Как это работает
slither . — компилирует проект и строит представление контрактов: наследование, функции, modifiers, переменные storage и внешние вызовы.
--detect — ограничивает анализ конкретными detectors. Это удобно для обучения или проверки одной категории риска.
--exclude — выключает detectors, которые не нужны проекту. Например, naming-convention часто шумит в учебных контрактах.
--json и --sarif — делают результат машинно-читаемым. Так Slither можно запускать в CI и прикладывать findings к pull request.
--filter-paths — убирает findings из зависимостей. Вы анализируете свой код, а не весь node_modules.
Частые ошибки
Запускать Slither только перед релизом → добавьте его в CI, чтобы ошибки ловились в каждом PR.
Игнорировать medium findings → многие реальные атаки начинаются с "не критичного" warning.
Фильтровать весь OpenZeppelin и свой код рядом с ним → проверяйте regex в --filter-paths, чтобы случайно не скрыть свои контракты.
Что дальше
- Аудит чеклист перед деплоем — как встроить Slither в общий pre-deploy процесс
- Reentrancy — атака и защита — пример уязвимости, которую Slither может найти автоматически
- Verify контракта в Etherscan — как опубликовать исходники после анализа и деплоя