Comment prévenir les attaques d'infinite mint en Solidity

Auteur de l’article

Une attaque de frappe infinie se produit lorsqu’un contrat de token permet à un attaquant de créer des tokens sans autorisation valable, sans faire respecter un plafond maximal, ou les deux. L’attaquant frappe un solde arbitraire, puis vend, échange, dépose ou collatéralise ces tokens nouvellement créés avant que les marchés et les intégrations ne puissent réagir.

La conséquence n’est pas seulement l’inflation. La frappe infinie peut détruire la valeur d’échange d’un token, vider les pools de liquidité, et créer des collatéraux non adossés dans les systèmes de prêt ou de trésorerie. Elrond a enregistré une perte de 113,0 M$ le 2022-06-05 lors d’un incident classé comme Infinite Mint, illustrant comment une limite d’émission défectueuse peut entraîner une perte à l’échelle de l’écosystème.

Qu’est-ce qu’une attaque de frappe infinie et comment fonctionne-t-elle ?

Une attaque de frappe infinie exploite un chemin d’émission de tokens qui ne prouve pas de manière fiable qui peut frapper et dans quelle mesure. Une fonction mint publique ou mal protégée permet à un attaquant de créer des soldes que le reste du protocole considère comme des tokens ERC-20 légitimes.

Une fonction de frappe est sûre uniquement lorsque l’autorisation du détenteur qui l’appelle, les conditions d’émission et le comptage de l’offre s’alignent sur la conception économique du protocole. Si n’importe quel appelant peut atteindre une logique équivalente à _mint, ou si un appelant privilégié peut contourner un plafond d’offre, la rareté du token n’est qu’une supposition.

Une attaque de frappe infinie suit généralement cette séquence :

  1. L’attaquant identifie un chemin d’émission accessible extérieurement ou une vérification d’accès facilement contournable.
  2. L’attaquant appelle la fonction avec un destinataire et un montant contrôlés par lui.
  3. Le contrat augmente le solde de l’attaquant et souvent la totalSupply.
  4. L’attaquant transfère les tokens frappés dans un pool DEX, un marché de prêt, un pont, ou un coffre-fort.
  5. L’attaquant échange des tokens artificiels contre de vrais actifs ou les utilise en tant que collatéral.
  6. Les fournisseurs de liquidité, prêteurs et détenteurs de tokens absorbent la perte économique résultante.

Les vulnérabilités liées à la frappe infinie sont particulièrement dangereuses lorsque les soldes de tokens sont acceptés par d’autres contrats sans vérification indépendante de leur origine. Un protocole de prêt ne fait pas de distinction entre les tokens frappés via des émissions prévues et ceux frappés via un contrôle d’accès manquant.

Quels schémas Solidity provoquent des vulnérabilités de frappe infinie ?

Les vulnérabilités de frappe infinie naissent généralement d’un manque d’autorisation, d’absence de limite d’offre, ou d’une autorisation qui, en apparence, est correcte mais accessible via une voie administrative non intentionnelle. Passez en revue chaque fonction pouvant augmenter un solde, directement ou indirectement.

Le schéma le plus évident est une fonction mint publique sans restriction sur l’appelant :

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

Le même risque existe lorsqu’un développeur contrôle la mauvaise identité. Par exemple, tx.origin ne devrait pas définir une autorité de frappe, car un attaquant peut faire appeler un portefeuille privilégié à un contrat intermédiaire malveillant. De même, vérifier si un destinataire est privilégié ne prouve pas que l’appelant est autorisé à émettre des tokens.

Parmi les autres causes courantes :

  • Une fonction setMinter accessible à n’importe quel compte, permettant à un attaquant de s’accorder des droits d’émission.
  • Un proxy upgradable dont l’autorité de mise à jour peut remplacer les restrictions de frappe.
  • Un pont ou gestionnaire cross-chain qui fait confiance à des messages arbitraires comme instructions de frappe.
  • Un plafond appliqué dans une fonction de frappe mais pas dans d’autres routes d’émission, comme les récompenses ou les migrations.
  • Des erreurs arithmétiques ou de conversion d’unités rendant un plafond nominal inefficace.
  • Un comptage de brûlures et frappes où les brûlures ne sont pas réellement vérifiées avant de distribuer de nouveaux tokens.

Une variable totalSupply seule ne constitue pas un contrôle de l’offre. Le contrat doit rejeter toute frappe entraînant que totalSupply + amount dépasse le maximum prévu. Cette invariant doit s’appliquer à chaque route d’émission, y compris la récupération administrative, la frappe via pont, les récompenses, et les migrations.

À quoi ressemble un code Solidity vulnérable ou corrigé face à la frappe infinie ?

Un contrat vulnérable à la frappe infinie expose une fonction d’émission non restreinte. Tout compte externe peut frapper un montant quelconque pour lui-même, sans limite de plafond.

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

contract TokenFrappeInfinieVulnérable {
    string public constant name = "Token Vulnérable";
    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 {
        // VULNÉRABLE : n'importe quel appelant peut créer des tokens arbitraires.
        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, "solde insuffisant");

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

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

La version corrigée sépare l’administrateur des minters autorisés et applique un plafond maximal avant chaque augmentation de solde. Le plafond n’est pas un substitut à l’autorisation, et l’autorisation ne remplace pas un plafond. Les deux contrôles traitent des modes de défaillance différents.

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

contract TokenAvecPlafondEtRôles {
    string public constant name = "Token Plafonné";
    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 MinterMisAJour(address indexed minter, bool allowed);

    modifier onlyAdmin() {
        require(msg.sender == admin, "pas admin");
        _;
    }

    modifier onlyMinter() {
        require(isMinter[msg.sender], "pas minter");
        _;
    }

    constructor(uint256 maxSupply_) {
        require(maxSupply_ > 0, "plafond nul");
        admin = msg.sender;
        maxSupply = maxSupply_;
        isMinter[msg.sender] = true;
    }

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

    function mint(address to, uint256 amount) external onlyMinter {
        // CORRIGÉ : l’émission autorisée ne peut dépasser le plafond immuable.
        require(totalSupply + amount <= maxSupply, "plafond dépassé");

        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, "solde insuffisant");

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

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

Si votre protocole prévoit une frappe via récompenses, ponts, partages dans un coffre, ou migrations, une audit de smart-contract et revue de sécurité peut remonter chaque voie d’émission à sa source d’autorisation et à sa limite d’offre avant déploiement.

Comment empêcher les attaques de frappe infinie en Solidity ?

Empêcher les attaques de frappe infinie nécessite une conception d’émission en couches : une autorité explicite, des contraintes d’offre imposées, des pouvoirs administratifs restreints, et des tests prouvant qu’aucune autre voie ne peut créer de soldes. La conception appropriée dépend que l’offre soit fixe, plafonnée, basée sur une émission, adossée à un collatéral, ou sur un pont.

Technique Ce qu’elle empêche Coût en gaz ou complexité Limitation
role-gated mint Création arbitraire de tokens par des acteurs externes Lecture de stockage pour la vérification du rôle Un minter compromis peut toujours frapper dans son autorité
Plafond maximal immuable Dépasser la quantité prévue dans l’émission Une vérification arithmétique par frappe Ne prévient pas une partie autorisée de frapper prématurément le plafond
Rôles séparés d’administrateur et de minter Se donner silencieusement plus d’autorité Code de gestion de rôles additionnel L’administrateur reste une frontière de confiance critique
Administration multisignature ou avec délai Changements à un seul clé sur les minters ou la configuration d’émission Délais opérationnels et gestion governance Ne corrige pas une logique de frappe déjà déployée et défectueuse
Chemin centralisé _mint interne Vérifications de plafond omises dans d’autres fonctions d’émission Refonte nécessaire Les revues doivent toujours examiner chaque route externe vers _mint
Surveillance des événements de frappe Détection retardée d’émissions anormales Infrastructure de monitoring hors chaîne La surveillance ne peut pas annuler une frappe malveillante déjà validée

Pour les tokens à offre fixe, le schéma le plus robuste consiste souvent à frapper l’intégralité de l’allocation lors du déploiement et supprimer toute capacité de frappe ultérieure. Pour les tokens d’émission, définir un calendrier mesurable, faire respecter le plafond global dans la fonction interne d’émission partagée, et s’assurer que chaque fonction externe a un but d’autorisation distinct.

La méthodologie Soken considère la frappe comme une frontière de création d’actifs, et non comme une fonction de commodité. Chaque voie augmentant un solde de token doit comporter un modèle d’autorisation documentée, une limite économique explicite, et une invariant testable.

Quels incidents réels ont été classés comme attaques de frappe infinie ?

Les incidents de frappe infinie enregistrés montrent que les défauts d’émission de tokens affectent aussi bien les actifs établis que les protocoles plus récents, sur plusieurs chaînes. Les incidents ci-dessous sont classés comme Infinite Mint dans la base de données des hacks de DefiLlama.

Protocole Date Montant perdu Chaîne
Elrond 2022-06-05 113,0 M$ Elrond
Paid Network 2021-03-05 27,0 M$ Ethereum
Gala 2024-05-20 22,3 M$ Ethereum
Haven Protocol 2021-07-03 8,2 M$ Haven
OcelotDex 2024-09-20 4,9 M$ Ethereum
TSR 2026-06-01 2,5 M$ BSC
Raydium AMM 2026-06-10 1,3 M$ Solana
Flooring Protocol 2026-06-08 500 K$ Ethereum

Ces incidents partagent une propriété économique fondamentale : une fois que des tokens non adossés entrent sur un marché intégré, l’attaque dépasse le contrat de token. Les pools de liquidité achètent l’offre artificielle, les marchés de prêt peuvent l’accepter comme collatéral, et les ponts ou coffres-forts peuvent propager le solde dans d’autres systèmes.

La question de revue pertinente est donc plus large que « Un attaquant peut-il appeler mint ? » Il s’agit de « N’importe quelle voie non fiable ou trop confiée peut-elle faire reconnaître à la plateforme des tokens non adossés comme des actifs valides ? »

Comment détecter une vulnérabilité de frappe infinie avant déploiement ?

La détection des vulnérabilités de frappe infinie nécessite de cartographier toutes les transitions d’état qui augmentent les soldes, puis de prouver que chaque transition est autorisée et maintient l’invariant de l’offre prévu. Une revue manuelle doit commencer par les contrats de tokens, mais doit continuer dans les ponts, coffres-forts, distributeurs de récompenses, modules de mise à niveau, et helpers administratifs.

Utilisez cette checklist de revue :

  1. Repérez chaque écriture sur les soldes, parts, compteurs d’offre, et fonctions de frappe internes.
  2. Vérifiez que chaque chemin d’émission externe possède une autorisation d’appel adaptée à son but.
  3. Confirmez que chaque chemin applique la même limite ou contrainte d’émission.
  4. Passez en revue les fonctions qui ajoutent, retirent, ou remplacent des minters et administrateurs.
  5. Tracez les chemins de mise à niveau, pont, migration, et callback pouvant atteindre la logique de frappe.
  6. Vérifiez si des comptes privilégiés peuvent modifier le plafond, l’émetteur, ou l’unité d’évaluation de façon imprévue.
  7. Vérifiez que les événements de frappe et la totalSupply correspondent à la création réelle de soldes.
  8. Testez les intégrations qui acceptent le token en tant que collatéral, actif de liquidité, ou dans un coffre-fort.

Slither est utile pour recenser les fonctions accessibles extérieurement, les changements d’état privilégiés, et les motifs suspects de contrôle d’accès, mais ne peut pas établir que le modèle d’offre d’un protocole est économiquement correct. La réflexion manuelle est essentielle pour les voies d’émission indirectes et l’autorité entre contrats.

Le fuzzing avec Foundry peut tester que des appelants arbitraires ne peuvent pas frapper et que l’offre ne dépasse jamais le plafond. Les tests d’invariance sont particulièrement efficaces car ils expriment directement la propriété de sécurité :

function invariant_supplyNeverExceedsCap() public view {
    require(token.totalSupply() <= token.maxSupply(), "limite d’offre dépassée");
}

Une seconde invariant doit assurer que seuls des acteurs approuvés peuvent augmenter l’offre. Dans la méthodologie de revue Soken, cette propriété est testée sur toutes les fonctions publiques, et pas seulement celle nommée mint. Pour plus de détails sur le contrôle d’accès, la comptabilité des tokens, et les risques associés, consultez le Hub Soken.

Insight sécurité : La méthodologie Soken considère que chaque nouvelle unité de token est une responsabilité créée par le protocole. Si le contrat ne peut pas prouver qui a autorisé cette responsabilité et pourquoi elle reste dans le cadre du modèle d’émission, la voie de frappe devient une frontière de sécurité nécessitant une refonte.

Un contrôle de rôle et un plafond d’offre transforment une émission non limitée en une opération encadrée et responsable, mais uniquement si chaque voie de frappe y recourt. La tâche d’ingénierie cruciale consiste à centraliser la création de soldes et rendre toute dérogation impossible par conception.

Avant lancement ou mise à niveau, rédigez l’invariant d’offre prévu en langage clair, implémentez-le dans la route partagée de frappe, et faites respecter avec des tests d’invariance Foundry.

Auteur de l’article

Questions fréquemment posées

Qu'est-ce qu'une attaque d'infinite mint en Solidity?

Une attaque d'infinite mint survient lorsqu'un attaquant peut créer des tokens sans autorisation valide, ou sans limite maximale de supply. L'attaquant obtient ainsi des balances que le protocole considère comme légitimes ERC-20.

Comment fonctionne une attaque d'infinite mint?

Elle exploite un processus d'émission de tokens sans vérifier qui peut mint ou combien de supply peut exister. Une fonction mint publique ou mal protégée permet de créer des balances considérées comme légitimes par le protocole.

Quels dégâts une telle attaque peut-elle causer?

Elle peut détruire la valeur d'échange d'un token via une inflation incontrôlée. Les tokens récemment minted peuvent être vendus, échangés ou utilisés comme collatéral, impactant la liquidité et les systèmes de prêt.

Que s'est-il passé avec l'incident d'infinite mint d'Elrond?

Elrond a perdu 113 millions de dollars en juin 2022 lors d'une attaque d'infinite mint. Cet incident montre qu'une faille dans les limites d'émission peut causer des pertes à l'échelle de l'écosystème.

Comment les développeurs Solidity peuvent-ils prévenir ces attaques?

Ils doivent assurer que la contrat prouve qui peut mint et combien de supply peut exister, en protégeant chaque chemin de mint avec une autorisation valide et en appliquant une limite maximale.

Chat