китаев.tech

Slither — статический анализ контрактов

Как установить Slither, запустить статический анализ Solidity-контрактов и читать findings перед деплоем.

Что делает Slither

Slither — это статический анализатор Solidity и Vyper-контрактов. Он читает код без деплоя и ищет паттерны, которые часто приводят к уязвимостям.

Slither не заменяет аудит, но быстро ловит типовые ошибки: tx.origin, reentrancy, опасные low-level calls, неправильные modifiers, shadowing, dead code и подозрительные зависимости.


Устанавливаем и запускаем Slither

Установите Slither:

bash
uv tool install slither-analyzer

Если uv не используется:

bash
pip install slither-analyzer

Запуск в Hardhat или Foundry-проекте:

bash
slither .

Запуск одного файла:

bash
slither contracts/SlitherDemo.sol

Вывод в JSON для CI:

bash
slither . --json slither-results.json

Проверяем контракт с ошибками

Создайте файл contracts/SlitherDemo.sol:

solidity
// 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();
        }
    }
}

Запустите анализ:

bash
slither contracts/SlitherDemo.sol

Slither должен подсветить опасные места в UnsafeTreasury: проверку через tx.origin и внешний call до обновления state.


Как читать findings

Finding Slither обычно отвечает на три вопроса:

text
Что найдено: tx.origin используется для авторизации
Где найдено: contracts/SlitherDemo.sol, withdrawAll()
Почему опасно: другой контракт может заставить owner вызвать вашу функцию

Сначала исправляйте high и medium findings. Low и informational тоже смотрите, но не блокируйте деплой только из-за стиля имени переменной.

Если finding ложноположительный, не игнорируйте его молча. Оставьте комментарий в PR или добавьте triage-запись, чтобы команда понимала решение.


Фильтруем и настраиваем запуск

Показать все detectors:

bash
slither --list-detectors

Запустить только конкретные detectors:

bash
slither . --detect reentrancy-eth,tx-origin

Исключить шумные detectors:

bash
slither . --exclude naming-convention,unused-state

Не показывать зависимости:

bash
slither . --filter-paths "node_modules|openzeppelin"

Сохранить результат для GitHub code scanning или SARIF viewer:

bash
slither . --sarif slither-results.sarif

Конфиг для проекта

Создайте файл slither.config.json:

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
}

Запуск с конфигом:

bash
slither . --config-file slither.config.json

Для интерактивного скрытия известных findings используйте triage mode:

bash
slither . --triage-mode

Slither сохранит решения в 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, чтобы случайно не скрыть свои контракты.


Что дальше

Материалы китаev.tech публикуются в образовательных целях и не являются инвестиционной рекомендацией. Примеры кода и описания протоколов — для обучения; использование в продакшне на ваш собственный риск. Дисклеймер и политика конфиденциальности.