An infinite mint attack occurs when a token contract lets an attacker create tokens without valid authorization, without enforcing a maximum supply, or both. The attacker mints an arbitrary balance, then sells, swaps, deposits, or collateralises the newly created tokens before markets and integrations can react.
The consequence is not merely inflation. Infinite minting can destroy a token’s exchange value, drain liquidity pools, and create unbacked collateral in lending or treasury systems. Elrond was recorded as losing $113.0M on 2022-06-05 in an incident classified as Infinite Mint, showing how a broken issuance boundary can become an ecosystem-level loss.
What is an infinite mint attack and how does it work?
An infinite mint attack exploits a token issuance path that does not reliably prove who may mint and how much may exist. A public or incorrectly protected mint function lets an attacker create balances that the rest of the protocol treats as legitimate ERC-20 tokens.
A mint function is safe only when its caller authorization, issuance conditions, and supply accounting match the protocol’s economic design. If any caller can reach _mint-equivalent logic, or a privileged caller can bypass a supply ceiling, the token’s scarcity is only an assumption.
A typical infinite mint attack follows this sequence:
- The attacker identifies an externally callable mint path or bypassable access check.
- The attacker calls the function with an attacker-controlled recipient and amount.
- The contract increases the attacker’s balance and often
totalSupply. - The attacker transfers the minted tokens into a DEX pool, lending market, bridge, or vault.
- The attacker exchanges artificial tokens for real assets or uses them as collateral.
- Liquidity providers, lenders, and token holders absorb the resulting economic loss.
Infinite mint vulnerabilities are especially dangerous where token balances are accepted by other contracts without independently checking how those balances were created. A lending protocol does not distinguish between tokens minted through intended emissions and tokens minted through a missing access-control check.
Which Solidity patterns cause infinite mint vulnerabilities?
Infinite mint vulnerabilities usually arise from missing authorization, missing supply limits, or authorization that is correct in appearance but reachable through an unintended administrative path. Review every function that can increase a balance, directly or indirectly.
The most obvious pattern is a public mint function with no caller restriction:
function mint(address to, uint256 amount) external {
balanceOf[to] += amount;
totalSupply += amount;
}
The same risk exists when a developer checks the wrong identity. For example, tx.origin should not define mint authority because an attacker can induce a privileged wallet to call a malicious intermediary contract. Similarly, checking whether a recipient is privileged does not prove that the caller is allowed to issue tokens.
Other common causes include:
- A
setMinterfunction callable by any account, allowing attackers to grant themselves issuance rights. - An upgradeable proxy whose upgrade authority can replace mint restrictions.
- A bridge or cross-chain handler that trusts arbitrary messages as mint instructions.
- A cap enforced in one mint function but not in another issuance route, such as reward claims or migration functions.
- Arithmetic or unit conversion mistakes that make a nominal cap ineffective.
- Burn-and-mint accounting where burns are not actually verified before replacement tokens are issued.
A totalSupply variable alone is not a supply control. The contract must reject every mint that would make totalSupply + amount exceed the intended maximum supply. That invariant must apply across every issuance route, including administrative recovery, bridge minting, rewards, and migrations.
What does vulnerable and fixed infinite mint Solidity code look like?
A vulnerable infinite mint contract exposes an unrestricted issuance function. Any externally owned account can mint any amount to itself, and no maximum supply limits the damage.
// 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 {
// VULNERABLE: any caller can create arbitrary tokens.
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, "insufficient balance");
unchecked {
balanceOf[msg.sender] -= amount;
}
balanceOf[to] += amount;
emit Transfer(msg.sender, to, amount);
return true;
}
}
The fixed version separates the administrator from authorized minters and enforces a maximum supply before every balance increase. The cap is not a substitute for authorization, and authorization is not a substitute for a cap. Both controls address different failure modes.
// 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, "not admin");
_;
}
modifier onlyMinter() {
require(isMinter[msg.sender], "not minter");
_;
}
constructor(uint256 maxSupply_) {
require(maxSupply_ > 0, "zero cap");
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 {
// FIX: authorized issuance cannot exceed the immutable cap.
require(totalSupply + amount <= maxSupply, "cap exceeded");
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, "insufficient balance");
unchecked {
balanceOf[msg.sender] -= amount;
}
balanceOf[to] += amount;
emit Transfer(msg.sender, to, amount);
return true;
}
}
If your protocol has minting through rewards, bridging, vault shares, or migrations, a smart-contract audit and security review can trace each issuance route back to its authorization and supply invariant before deployment.
How do you prevent infinite mint attacks in Solidity?
Preventing infinite mint attacks requires a layered issuance design: explicit authority, enforced supply constraints, narrow administrative powers, and tests that prove no other path can create balances. The appropriate design depends on whether supply is fixed, capped, emissions-based, collateral-backed, or bridge-backed.
| Technique | What it stops | Gas or complexity cost | Limitation |
|---|---|---|---|
Role-gated mint |
Arbitrary external callers minting tokens | Storage read for the role check | A compromised minter can still mint within its authority |
| Immutable maximum supply | Minting beyond the designed token supply | One arithmetic check per mint | Does not prevent an authorized party from minting the full cap prematurely |
| Separate admin and minter roles | A minter silently granting itself more authority | Additional role-management code | The admin remains a critical trust boundary |
| Multisignature or timelocked administration | Single-key changes to minters or issuance configuration | Operational delay and governance overhead | Does not correct flawed mint logic already deployed |
Centralised internal _mint path |
Cap checks being omitted in secondary issuance functions | Refactoring effort | Reviewers must still find every external route into _mint |
| Event monitoring for mint activity | Delayed detection of abnormal issuance | Off-chain monitoring infrastructure | Monitoring cannot reverse an already valid malicious mint |
For fixed-supply tokens, the strongest pattern is often to mint the entire allocation during deployment and remove all later mint capability. For emissions-based tokens, define a measurable schedule, enforce the aggregate cap in the shared internal issuance function, and ensure each external function has a distinct authorization purpose.
Soken methodology treats minting as an asset-creation boundary, not a convenience function. Every route that increases token balances should have a documented authority model, an explicit economic limit, and a testable invariant.
Which real incidents were classified as infinite mint attacks?
Recorded infinite mint incidents show that token issuance flaws affect established assets and newer protocols across several chains. The incidents below are classified as Infinite Mint in the DefiLlama hacks database.
| Protocol | Date | Amount lost | 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 |
These incidents share a core economic property: once unbacked tokens enter an integrated market, the attack extends beyond the token contract. Liquidity pools buy the artificial supply, lending markets may accept it as collateral, and bridges or vaults may propagate the balance into further systems.
The relevant review question is therefore broader than, “Can an attacker call mint?” It is, “Can any untrusted or excessively trusted path cause the protocol to recognise unbacked tokens as valid assets?”
How do you detect an infinite mint vulnerability before deployment?
Detecting infinite mint vulnerabilities requires mapping all balance-increasing state transitions, then proving that each transition is authorized and preserves the intended supply invariant. A manual review should begin with token contracts, but must continue into bridges, vaults, reward distributors, upgrade modules, and administrative helpers.
Use this review checklist:
- Find every write to balances, shares, supply counters, and internal mint functions.
- Verify each external issuance path has caller authorization appropriate to its purpose.
- Confirm every path enforces the same cap or emissions constraint.
- Review functions that add, remove, or replace minters and administrators.
- Trace upgrade, bridge, migration, and callback paths that can reach mint logic.
- Check whether privileged accounts can change the cap, issuer, or accounting unit unexpectedly.
- Verify that mint events and
totalSupplymatch actual balance creation. - Test integrations that accept the token as collateral, liquidity, or vault assets.
Slither is useful for enumerating externally callable functions, privileged state changes, and suspicious access-control patterns, but it cannot establish that a protocol’s supply model is economically correct. Manual reasoning is essential for indirect mint paths and cross-contract authority.
Foundry fuzzing can test that arbitrary callers cannot mint and that supply never exceeds the cap. Invariant tests are particularly effective because they express the security property directly:
function invariant_supplyNeverExceedsCap() public view {
require(token.totalSupply() <= token.maxSupply(), "supply cap broken");
}
A second invariant should assert that only approved actors can increase supply. In Soken review methodology, that property is tested across all public functions, not only the function named mint. For additional research on access control, token accounting, and related contract risks, visit the Soken Hub.
Security insight: Soken methodology treats each new token unit as a liability created by the protocol. If the contract cannot prove who authorized that liability and why it remains within the issuance model, the mint path is a security boundary requiring redesign.
A role check and supply cap turn unrestricted issuance into a bounded, accountable operation, but only if every mint route uses them. The critical engineering task is to centralise balance creation and make bypasses impossible by construction.
Before launch or upgrade, write the intended supply invariant in plain language, implement it in the shared mint path, and enforce it with Foundry invariant tests.