Un attacco di minting infinito si verifica quando un contratto di token consente a un attaccante di creare token senza autorizzazione valida, senza far rispettare un massimo di emissione, o entrambi. L’attaccante conia un saldo arbitrario, quindi vende, scambia, deposita o collateralizza i token appena creati prima che i mercati e le integrazioni possano reagire.
La conseguenza non è solo inflazione. La conia infinita può distruggere il valore di scambio di un token, prosciugare i pool di liquidità e creare collateral privo di supporto nei sistemi di prestito o di tesoreria. Elrond è stato registrato aver perso $113,0M il 2022-06-05 in un incidente classificato come Infinite Mint, mostrando come un limite di emissione rotto possa trasformarsi in una perdita a livello di ecosistema.
Cos’è un attacco di infinite mint e come funziona?
Un attacco di infinite mint sfrutta un percorso di emissione di token che non prova affidabilmente chi può coniare e quanto può esistere. Una funzione mint pubblica o mal protetta permette a un attaccante di creare saldi che il resto del protocollo tratta come token ERC-20 legittimi.
Una funzione di minting è sicura solo quando l’autorizzazione del chiamante, le condizioni di emissione e la contabilizzazione dell’offerta rispettano il design economico del protocollo. Se qualsiasi chiamante può raggiungere una logica equivalente a _mint, o un chiamante privilegiato può bypassare un limite di emissione, la scarsità del token è solo un’ipotesi.
Un attacco di minting infinito tipico segue questa sequenza:
- L’attaccante identifica un percorso di minting chiamabile esternamente o un controllo di accesso eludibile.
- L’attaccante chiama la funzione con un destinatario e un importo controllati da lui.
- Il contratto aumenta il saldo dell’attaccante e spesso anche
totalSupply. - L’attaccante trasferisce i token coniati in un pool DEX, sul mercato di prestito, tramite bridge o vault.
- L’attaccante scambia token artificiali per asset reali o li utilizza come collateral.
- I fornitori di liquidità, i prestatori e i detentori di token subiscono la perdita economica risultante.
Le vulnerabilità di infinite mint sono particolarmente pericolose dove i saldi dei token sono accettati da altri contratti senza verificare indipendentemente come siano stati creati. Un protocollo di prestito, ad esempio, non distingue tra token coniati attraverso emissioni programmate e token coniati senza un controllo di accesso.
Quali pattern di Solidity causano vulnerabilità di infinite mint?
Le vulnerabilità di infinite mint di solito derivano da mancanza di autorizzazione, assenza di limiti di emissione, o autorizzazioni che sembrano corrette ma sono raggiungibili tramite percorsi amministrativi non intenzionati. Esamina ogni funzione che può aumentare un saldo, direttamente o indirettamente.
Il pattern più ovvio è una funzione mint pubblica senza restrizioni sul chiamante:
function mint(address to, uint256 amount) external {
balanceOf[to] += amount;
totalSupply += amount;
}
Lo stesso rischio si presenta quando uno sviluppatore controlla l’identità sbagliata. Per esempio, tx.origin non dovrebbe definire l’autorità di minting perché un attaccante può indurre un wallet privilegiato a chiamare un contratto intermediario malicioso. Allo stesso modo, verificare se un destinatario è privilegiato non dimostra che il chiamante sia autorizzato a emettere token.
Altri cause comuni includono:
- Una funzione
setMinterchiamabile da qualsiasi account, che permette agli attaccanti di concedersi diritti di emissione. - Un proxy aggiornabile il cui potere di upgrade può sostituire restrizioni di minting.
- Un bridge o gestore cross-chain che si fida di messaggi arbitrari come istruzioni di minting.
- Una soglia (cap) applicata in una funzione di minting, ma non in altre rotte di emissione, come richieste di ricompense o funzioni di migrazione.
- Errori di aritmetica o di conversione di unità che rendono inefficace un limite nominale.
- Contabilizzazione di burn-and-mint in cui i burn non sono verificati prima di emettere token sostitutivi.
Una variabile totalSupply da sola non è un controllo dell’offerta. Il contratto deve rifiutare ogni mint che faccia sì che totalSupply + amount superi il massimo previsto. Questo invariato deve essere valido per ogni rotta di emissione, inclusi recuperi amministrativi, minting tramite bridge, ricompense e migrazioni.
Come appare il codice Solidity vulnerabile e corretto di infinite mint?
Un contratto vulnerabile di infinite mint espone una funzione di emissione senza restrizioni. Qualsiasi account esterno può coniare qualsiasi quantità e senza limiti di emissione il danno può essere significativo.
// 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 {
// VULNERABILE: qualsiasi chiamante può creare token arbitrari.
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, "Saldo insufficiente");
unchecked {
balanceOf[msg.sender] -= amount;
}
balanceOf[to] += amount;
emit Transfer(msg.sender, to, amount);
return true;
}
}
La versione corretta separa l’amministratore dai minter autorizzati e applica un massimo di emissione prima di ogni aumento di saldo. Il limite non sostituisce l’autorizzazione, né l’autorizzazione sostituisce il limite. Entrambi i controlli affrontano modalità di fallimento diverse.
// 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, "non admin");
_;
}
modifier onlyMinter() {
require(isMinter[msg.sender], "non minter");
_;
}
constructor(uint256 maxSupply_) {
require(maxSupply_ > 0, "massimo di emissione zero");
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 {
// CORRETTO: emissione autorizzata che non supera il massimo immutabile.
require(totalSupply + amount <= maxSupply, "superato il limite");
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, "Saldo insufficiente");
unchecked {
balanceOf[msg.sender] -= amount;
}
balanceOf[to] += amount;
emit Transfer(msg.sender, to, amount);
return true;
}
}
Se il tuo protocollo ha meccanismi di minting tramite ricompense, bridge, quote di vault o migrazioni, una auditing di smart contract e una revisione di sicurezza può tracciare ogni rotte di emissione alla sua autorizzazione e invariato dell’offerta prima del deployment.
Come prevenire attacchi di infinite mint in Solidity?
Prevenire attacchi di infinite mint richiede un design stratificato di emissione: autorità esplicita, vincoli di offerta applicati, poteri amministrativi ristretti e test che dimostrino che nessun’altra via può creare saldi. Il design appropriato dipende dal tipo di offerta: fissa, limitata, basata su emissioni, collateralizzata o basata su bridge.
| Tecnica | Cosa impedisce | Costo in gas o complessità | Limite |
|---|---|---|---|
mint con ruolo |
Minting da chiamanti esterni arbitrari | Lettura di storage per controllo ruolo | Un minter compromesso può ancora mintare entro la sua autorità |
| Supposto massimo immutabile | Mint oltre il massimo previsto | Un check aritmetico per ogni mint | Non impedisce a un soggetto autorizzato di mintare prematuramente l’intera quota |
| Ruoli separati di amministratore e minter | Un minter si concede silenziosamente più autorità | Codice di gestione ruoli aggiuntivo | L’amministratore rimane un confine di fiducia critico |
| Gestione multisignature o a time lock | Cambiamenti individuali ai minter o configurazioni di emissione | Ritardo operativo e sovrastruttura di governance | Non corregge logiche di minting difettose già deployate |
Percorso centralizzato _mint interno |
Mancata verifica del limite in funzioni secondarie | Riprogettazione necessaria | I revisori devono ancora verificare tutte le rotte esterne verso _mint |
| Monitoraggio eventi di attività di mint | Rilevamento tardivo di emissioni anomale | Monitoraggio off-chain | Il monitoraggio non può annullare un mint già valido e dannoso |
Per token a offerta fissa, il pattern più forte è spesso coniare l’intera allocazione durante il deploy e rimuovere tutte le capacità di mint successivo. Per token basati su emissioni, definire un programma misurabile, applicare il limite aggregato nella funzione condivisa di emissione e assicurarsi che ogni funzione esterna abbia una autorizzazione distinta.
La metodologia di Soken considera il mint come un limite alla creazione di asset, non come una funzione di convenienza. Ogni rotta che aumenta i saldi di token dovrebbe avere un modello di autorizzazione documentato, un limite economico esplicito e un invariato verificabile.
Quali incidenti reali sono stati classificati come attacchi di infinite mint?
Gli incidenti di infinite mint registrati mostrano che i difetti di emissione di token interessano asset consolidati e protocolli più recenti su diverse chains. Gli incidenti sottostanti sono classificati come Infinite Mint nel database di hack di DefiLlama.
| Protocollo | Data | Importo perso | Chain |
|---|---|---|---|
| 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 |
Questi incidenti condividono una proprietà economica fondamentale: una volta che token non supportati entrano in un mercato integrato, l’attacco si estende oltre il contratto del token. I pool di liquidità acquistano l’offerta artificiale, i mercati di prestito possono accettarla come collateral, e bridge o vault possono propagate il saldo in sistemi ulteriori.
La domanda di revisione pertinente è dunque più ampia di “Un attaccante può chiamare mint?” È piuttosto: “Può qualsiasi percorso non affidabile o eccessivamente affidabile causare che il protocollo riconosca token non supportati come asset validi?”
Come si rileva una vulnerabilità di infinite mint prima del deployment?
Rilevare vulnerabilità di infinite mint richiede mappare tutte le transizioni di stato che aumentano i saldi, dimostrando poi che ogni transizione è autorizzata e preserva l’invariante di emissione previsto. Una revisione manuale dovrebbe cominciare dai contratti di token, ma deve continuare in bridge, vault, distributori di ricompense, moduli di upgrade e helper amministrativi.
Segui questa checklist di revisione:
- Trova ogni scrittura su saldi, quote, contatori di offerta e funzioni di minting interne.
- Verifica che ogni rotta di emissione esterna abbia l’autorizzazione del chiamante appropriata.
- Conferma che ogni rotta applichi lo stesso limite o vincolo di emissione.
- Rivedi funzioni che aggiungono, rimuovono o sostituiscono minter e amministratori.
- Traccia i percorsi di upgrade, bridge, migrazione e callback che possono raggiungere la logica di minting.
- Controlla se account privilegiati possono cambiare inaspettatamente il limite, l’emittente o l’unità di contabilità.
- Verifica che gli eventi di mint e
totalSupplycorrispondano alla reale creazione di saldi. - Testa le integrazioni che accettano il token come collateral, asset di liquidità o vault.
Slither è utile per elencare funzioni chiamabili esternamente, cambiamenti di stato privilegiati e pattern sospetti di controllo accesso, ma non può stabilire che il modello di offerta di un protocollo sia economicamente corretto. La ragionamento manuale è essenziale per le rotte di minting indirette e per l’autorità tra contratti.
Il fuzzing di Foundry può testare che chiamanti arbitrari non possano mintare e che l’offerta non superi mai il limite. I test di invariato sono particolarmente efficaci perché esprimono direttamente la proprietà di sicurezza:
function invariant_supplyNeverExceedsCap() public view {
require(token.totalSupply() <= token.maxSupply(), "superato il limite di offerta");
}
Una seconda invariato dovrebbe assicurare che solo attori approvati possano aumentare l’offerta. Nella metodologia di revisione di Soken, questa proprietà viene testata su tutte le funzioni pubbliche, non solo sulla funzione mint. Per approfondimenti su controllo degli accessi, accounting dei token e rischi correlati, visita il Soken Hub.
Insight di sicurezza: La metodologia di Soken tratta ogni nuova unità di token come un obbligo creato dal protocollo. Se il contratto non riesce a dimostrare chi ha autorizzato quell’obbligo e perché rimane all’interno del modello di emissione, il percorso di minting diventa un confine di sicurezza che richiede redesign.
Un controllo di ruolo e un limite di offerta trasformano un’emissione illimitata in un’operazione limitata e responsabile, ma solo se utilizzati in ogni rotta di mint. L’attività critica di ingegneria è centralizzare la creazione di saldi e rendere impossibile bypassare le restrizioni tramite costruzione.
Prima del lancio o aggiornamento, scrivi in linguaggio semplice l’invariante di offerta prevista, implementalo nel percorso condiviso di minting e fallalo con test di invariato di Foundry.