Як запобігти атакі безмежної Mint у Solidity

Автор статті

Що таке атака безмежного друку та як вона працює?

Атака безмежного друку виникає, коли контракт із токенами дозволяє зловмиснику створювати токени без правильного авторизації, без обмеження максимальної кількості або й того й іншого одночасно. Зловмисник виконує “міні” на довільний баланс, потім продає, обмінює, депонує або закладає нововипущені токени до моменту, коли ринки та інтеграції зможуть відреагувати.

Наслідки — це не просто інфляція. Необмежене друкування може зруйнувати обмінну вартість токена, висмоктати ліквідність з пулів, а також створити необґрунтований collateral у системах кредитування або казначейства. 05.06.2022 року Elrond зафіксували збитки на суму $113.0M у випадку, класифікованому як Infinite Mint, що ілюструє, як порушення межі емісії може призвести до втрат на рівні екосистеми.

Що таке атака безмежного друку і як вона працює?

Атака безмежного друку експлуатує шлях емісії токенів, який не дає змоги надійно визначити, хто та скільки має права на емісію. Публічна або неправильно захищена функція mint дозволяє зловмиснику створювати баланси, що вважаються легітимними ERC-20 токенами.

Функція mint безпечна лише тоді, коли її виконавець має відповідні права, емісійні умови та облік пропозиції відповідають економічному дизайну протоколу. Якщо будь-хто може викликати логіку, подібну до _mint, або привілейований користувач може обійти обмеження на сукупну емісію, то дефіцит у токена стає лише припущенням.

Типова послідовність атаки безмежного друку виглядає так:

  1. Зловмисник знаходить шлях зовнішнього виклику mint або обходить контроль доступу.
  2. Зловмисник викликає функцію, передаючи контрольованого отримувача і суму.
  3. Контракт збільшує баланс зловмисника і, зазвичай, totalSupply.
  4. Зловмисник переносить створені токени до пули DEX, ринку кредитування, моста або сховища.
  5. Зловмисник обмінює штучні токени на реальні активи або використовує їх як collateral.
  6. Провайдери ліквідності, кредитори та власники токенів зазнають економічних збитків.

Уразливості типу infinite mint особливо небезпечні там, де баланси токенів приймаються іншими контрактами без незалежної перевірки способу їх створення. Протокол кредитування не відрізняє емісію через заплановані випуски від тих, що виникли через відсутність контролю доступу.

Які шаблони Solidity спричиняють уразливості infinite mint?

Уразливості безмежного друку переважно виникають через відсутність авторизації, відсутність обмежень за кількістю або через авторизацію, що виглядає правильно, але доступна через небажаний адміністративний шлях. Ретельно переглядайте кожну функцію, яка може збільшити баланс, прямо або опосередковано.

Найочевидніший шаблон — публічна функція mint без обмежень щодо виконавця:

function mint(address to, uint256 amount) external {
    balanceOf[to] += amount;
    totalSupply += amount;
}

Такий ризик має місце, коли розробник перевіряє неправильну ідентичність. Наприклад, tx.origin не повинен визначати права на емісію, оскільки зловмисник може спонукати привілейований гаманець викликати шкодливий проміжний контракт. Аналогічно, перевірка привілейованості отримувача не доводить, що виконавець має право емісії.

До інших поширених причин належать:

  • Функція setMinter, яку може викликати будь-хто, що дозволяє зловмиснику наділити себе правами емісії.
  • Оновлюваний проксі, що може змінити обмеження на друк або емісію.
  • Мости або крос-ланч-хендлери, що довіряють будь-яким повідомленням як інструкціям на друк.
  • Обмеження у одній функції mint, яке відсутнє в інших маршрутах емісії, таких як заявка на нагороди або міграції.
  • Помилки в обчисленнях або перетвореннях одиниць, що роблять номінальний ліміт ефективно недійсним.
  • Облік Burn-and-mint, коли виконується несправжня перевірка спалень перед видачею замінних токенів.

Змінна totalSupply сама по собі не контролює пропозицію. Контракт має відхиляти будь-які емісії, що роблять totalSupply + amount більшим за максимальний обсяг, визначений у протоколі. Це invariant має поширюватися на всі маршрути емісії, включаючи адміністративне відновлення, мостову емісію, нагороди та міграції.

Як виглядає уразливий і виправлений код Solidity для infinite mint?

Уразливий контракт із безмежним друком відкриває доступну функцію емісії. Любий зовнішній аккаунт може створювати будь-яку кількість токенів для себе, і ніякі обмеження максимальної пропозиції не обмежують збитки.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract VulnerableInfiniteMintToken {
    string public constant name = "Vulnerable Token";
    string public constant symbol = "VULN";

    uint256 public totalSupply;
    mapping(address => uint256) public balanceOf;

    event Transfer(address indexed from, address indexed to, uint256 amount);

    function mint(address to, uint256 amount) external {
        // Уразливість: будь-хто може створювати довільні токени.
        totalSupply += amount;
        balanceOf[to] += amount;
        emit Transfer(address(0), to, amount);
    }

    function transfer(address to, uint256 amount) external returns (bool) {
        require(balanceOf[msg.sender] >= amount, "недостатньо балансу");

        unchecked {
            balanceOf[msg.sender] -= amount;
        }
        balanceOf[to] += amount;

        emit Transfer(msg.sender, to, amount);
        return true;
    }
}

Виправлений варіант відокремлює адміністратора від авторизованих емісіїв і вводить максимальну кількість контрактом перед кожним збільшенням балансу. Обмеження — не заміна авторизації, а контроль її. Обидва компоненти — контроль авторизації і обмеження — працюють у парі, щоб уникнути атак.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract CappedRoleMintToken {
    string public constant name = "Capped Token";
    string public constant symbol = "CAP";

    address public immutable admin;
    uint256 public immutable maxSupply;
    uint256 public totalSupply;

    mapping(address => bool) public isMinter;
    mapping(address => uint256) public balanceOf;

    event Transfer(address indexed from, address indexed to, uint256 amount);
    event MinterUpdated(address indexed minter, bool allowed);

    modifier onlyAdmin() {
        require(msg.sender == admin, "не адміністратор");
        _;
    }

    modifier onlyMinter() {
        require(isMinter[msg.sender], "не емісій");
        _;
    }

    constructor(uint256 maxSupply_) {
        require(maxSupply_ > 0, "нульовий ліміт");
        admin = msg.sender;
        maxSupply = maxSupply_;
        isMinter[msg.sender] = true;
    }

    function setMinter(address minter, bool allowed) external onlyAdmin {
        isMinter[minter] = allowed;
        emit MinterUpdated(minter, allowed);
    }

    function mint(address to, uint256 amount) external onlyMinter {
        // ВИПРАВЛЕННЯ: авторизована емісія не може перевищити необмінний ліміт.
        require(totalSupply + amount <= maxSupply, "перевищено ліміт");

        totalSupply += amount;
        balanceOf[to] += amount;
        emit Transfer(address(0), to, amount);
    }

    function transfer(address to, uint256 amount) external returns (bool) {
        require(balanceOf[msg.sender] >= amount, "недостатньо балансу");

        unchecked {
            balanceOf[msg.sender] -= amount;
        }
        balanceOf[to] += amount;

        emit Transfer(msg.sender, to, amount);
        return true;
    }
}

Для токенів із нагородами, мостами, пайовими фондами або міграціями рекомендується провести перевірку безпеки смарт-контрактів, яка дозволить простежити кожен маршрут емісії до його авторизації та інваріанту пропозиції перед розгортанням.

Як запобігти атакам безмежного друку у Solidity?

Щоб запобігти атакам безмежного друку, потрібно використовувати багаторівневий дизайн емісії: чітку авторизацію, контроль обмежень, вузький адміністративний вплив і тестування, що доводять, що жоден інший шлях не може створити баланс. Правильний підхід залежить від того, чи фіксована, обмежена, базується на емісіях, забезпечена collateral-ом або мостом пропозиція.

Метод Що він зупиняє Вартість Gas або складність Обмеження
Рольова mint Випадкові зовнішні виклики токенів Читання ролі з storage Зламаний minter може емісити у межах своїх прав
Необхідний maximum supply Випуск понад запланований обсяг Одна арифметична перевірка Не запобігає попередньому дуже швидкому друку повної емісії
Окремі ролі адміністратора і мінера Тихо додати собі більше прав Додатковий код управління ролями Адміністратор залишається важливим рівнем довіри
Мультипідпис або часова блокада Зміни з одним ключем Внутрішній запуск затримки і управління Не виправляє уже існуючі помилки логіки друку
Централізований прихований _mint Обліки перевірки обмежень пропущені Рефакторинг Переглядачам потрібно знайти всі зовнішні шляхи до _mint
Відстеження подій для активності друку Виявлення аномального випуску з затримкою Інфраструктура моніторингу внекоштовно або офлайн Моніторинг не може повернути вже здійснений злочинний друк

Для токенів із фіксованою пропозицією найефективніша стратегія — створити всю емісію під час розгортання і видалити можливість подальшого друку. Для токенів із емісіями рекомендовано визначити конкретний графік, застосувати обмеження у спільній внутрішній функції емісії та гарантувати, що кожна зовнішня функція має свій дозвіл.

Методологія Soken розглядає друк як границю створення активу, а не просто функцію. Кожен маршрут збільшення балансу повинен мати задокументовану модель авторизації, явний економічний ліміт і тестоване invariант.

Які фактичні інциденти класифікувалися як атаки Infinite Mint?

Загалом, понад 20 випадків, що були зафіксовані у базі даних халеп DefiLlama, належать до категорії Infinite Mint. Нижче наведено основні з них:

Протокол Дата Втрати Ланцюг
Elrond 2022-06-05 $113.0M Elrond
Paid Network 2021-03-05 $27.0M Ethereum
Gala 2024-05-20 $22.3M Ethereum
Haven Protocol 2021-07-03 $8.2M Haven
OcelotDex 2024-09-20 $4.9M Ethereum
TSR 2026-06-01 $2.5M BSC
Raydium AMM 2026-06-10 $1.3M Solana
Flooring Protocol 2026-06-08 $500K Ethereum

Усі ці випадки мають спільне економічне властивість: після входу необґрунтованих токенів у інтегровані ринки, ураження поширюється далеко за межі контракту з токенами. Пули ліквідності купують штучний Supply, ринки кредитування можуть приймати його як collateral, а мости або сховища — поширюють баланс далі.

Ключове питання — не лише: “Чи може зловмисник викликати mint?” А швидше: “Чи може будь-який недовірливий або надмірно довірливий маршрут змусити протокол визнати необґрунтовані токени валідними активами?”

Як виявити уразливість безмежного друку перед розгортанням?

Виявлення уразливості безмежного друку вимагає ретельного картування всіх переходів стану, які збільшують баланс, та доведення, що кожен перехід є авторизованим і зберігає інваріант пропозиції. ручний огляд слід починати з контрактів токенів, а потім перевірити мости, сховища, розподільники нагород, модулі оновлення і адміністративні помічники.

Використовуйте цей чекліст:

  1. Пошук усіх записів звернення до балансів, часток, лічильників пропозиції і внутрішніх функцій mint.
  2. Перевірка, що кожен зовнішній маршрут емісії має відповідний дозвіл виконавця.
  3. Перевірка, що кожен маршрут дотримується однакового обмеження або емісійного графіка.
  4. Аналіз функцій додавання, видалення або заміни мінтерів і адміністраторів.
  5. Відслідковування шляхів оновлення, мостів, міграції і зворотніх викликів, що можуть дійти до логіки mint.
  6. Перевірка, чи можуть привілейовані облікові записи несподівано змінювати ліміт, емісію або одиницю обліку.
  7. Перевірка відповідності Event-ів і totalSupply реальному створенню балансів.
  8. Тестування інтеграцій, які приймають токен як collateral, актив для ліквідності або активи для сховищ.

Slither корисний для переліку зовнішніх функцій, привілейованих змін стану та підозрілих шаблонів контролю доступу, але він не може довести, що модель пропозиції є економічно коректною. Ручне роздуми необхідні для аналізу опосередкованих шляхів емісії та перекриття пов’язаних з цим повноважень.

МодульFoundry дозволяє провести fuzzing-тестування: він перевіряє, що довільний виконавець не може здійснити емісію, і що пропозиція ніколи не перевищує ліміт. invariant-тести особливо ефективні, оскільки одразу фіксують безпекову властивість:

function invariant_supplyNeverExceedsCap() public view {
    require(token.totalSupply() <= token.maxSupply(), "перевищено ліміт");
}

Інший invariants — підтверджують, що лише дозволені особи можуть збільшити пропозицію. За методологією Soken ця властивість тестується для всіх публічних функцій, а не тільки для mint. Більш детальні рекомендації — на Soken Hub.

Інсайт безпеки: Методологія Soken розглядає кожен новий токен як актив-обов’язок, створений протоколом. Якщо контракт не може довести, хто і чому авторизував цей зобов’язання і чому воно залишилось у межах моделі емісії, шлях емісії — це безпекова межа, що потребує редизайну.

Контроль ролі і ліміт пропозиції перетворюють необмежену емісію у обмежену та підзвітну операцію, але лише якщо кожен маршрут друку використовує ці механізми. Ключове технічне завдання — централізувати створення балансів і зробити обходи неможливими з конструкції.

Перед запуском чи оновленням потрібно записати планований інваріант пропозиції людською мовою, реалізувати його в спільному маршруті mint і закріпити за допомогою invariant-тестів Foundry.

Автор статті

Часті запитання

Що таке атака безмежної Mint у Solidity?

Атака безмежної Mint у смарт-контракті Solidity дозволяє зловмиснику створювати необмежену кількість токенів без належної авторизації або без обмеження максимальної поставки, що дозволяє отримати фальсифіковані баланси.

Як працює атака безмежної Mint?

Вона використовує уразливий шлях issuance, де не підтверджується особа, яка може створювати токени, або не контролюється максимально можлива кількість. Відкриті або неправильно захищені функції mint дозволяють зловмиснику створювати недостовірні баланси.

Який шкода може спричинити атака безмежної Mint?

Вона може знищити обмінну цінність токена через неконтрольовану інфляцію. Зловмисник може продавати, обмінювати або використовувати нові токени як заставу, що веде до витоку ліквідності й створення необґрунтованого забезпечення.

Що трапилося з Elrond під час атаки безмежної Mint?

Elrond втратив $113M у інциденті 5 червня 2022 року, класифікованому як Infinite Mint. Цей випадок показує, що порушення issuance boundary може призвести до збитків на рівні екосистеми, коли ринки та інтеграції приймають новостворені токени.

Як розробники Solidity можуть запобігти атакам безмежної Mint?

Щоб запобігти такій атаці, контракт повиннен надійно підтверджувати, хто має право mint і скільки може бути створено. Захищайте всі шляхи mint авторизацією та вводьте обмеження поставок, щоб запобігти створенню фальсифікованих балансів.

Чат