NFT Dealers

First Flight #58
Beginner FriendlyFoundry
100 EXP
Submission Details
Impact: high
Likelihood: high

MockUSDC Vulnerability Disclosure

Author Revealed upon completion

Root + Impact

Description

  • Describe the normal behavior in one or more sentences

  • Explain the specific issue or problem in one or more sentences

  • The MockUSDC contract is a testnet ERC20 token implementation simulating USDC (6 decimals). It contains four critical design flaws that violate ERC20 standard best practices, break permission controls, and break realistic token economics. These flaws are present in the core functions of the contract:

    1. Unrestricted Minting: The mint function has no access controls, allowing any external address to mint unlimited tokens.

    2. Missing Burn Functionality: No implementation of burn/burnFrom functions, which are core to real stablecoin logic (redemption/value destruction).

    3. Uncapped Total Supply: No maximum supply limit, enabling infinite token minting even if access controls are added.

    4. Unsafe Approval Logic: No override of the approve function to mitigate front-running/approval replay attacks, a known vulnerability in ERC20 implementations.

// Root cause in the codebase with @> marks to highlight the relevant section
// @audit Critical: Unrestricted minting function allows any address to create infinite supply.
function mint(address to, uint256 amount) external {
_mint(to, amount);
}
// @audit Medium: Missing burn/burnFrom functions break redemption/value destruction logic testing.
// function burn(...) external { ... }
// @audit Low: Approval logic does not clear existing allowances before setting new ones (prone to front-running).
// function approve(...) external { ... }

Risk

Likelihood:

  • Certain: The unrestricted mint function is callable by any address, making exploitation trivial (no special conditions required).

  • High: Missing burn functionality breaks all testing flows requiring token destruction (e.g., staking withdrawal fees, tax mechanisms).

Impact:

  • Critical Economic Damage: Attackers can mint unlimited mUSDC, devaluing the token and breaking all testnet/staging environment economics (e.g., breaking staking reward calculations in dependent protocols).

  • Testing Invalidation: All test cases relying on realistic stablecoin supply dynamics (e.g., mint/burn parity) will produce invalid, misleading results.

Proof of Concept

// Attacker contract/EOA execution
MockUSDC mockUSDC = MockUSDC(0xYourMockUSDCAddress);
// Mint 1 billion mUSDC (6 decimals) to attacker address
mockUSDC.mint(0xAttackerAddress, 1_000_000_000 * 10**6);
// Verify balance: balanceOf(0xAttackerAddress) == 1e15 (1e9 * 1e6)
Poc 2
// Attempt to burn tokens (fails, no function exists)
mockUSDC.burn(0xAttackerAddress, 100 * 10**6);
// Transaction reverts with "FunctionNotFound" error

Recommended Mitigation

- remove this code
- function mint(address to, uint256 amount) external {
- _mint(to, amount);
- }
+ add this code
+ import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
+
+ contract MockUSDC is ERC20, Ownable {
+ uint256 public constant MAX_SUPPLY = 1_000_000_000 * 10**6;
+
+ constructor() ERC20("MockUSDC", "mUSDC") Ownable(msg.sender) {}
+
+ function mint(address to, uint256 amount) external onlyOwner {
+ if (to == address(0)) revert MintToZeroAddress();
+ if (totalSupply() + amount > MAX_SUPPLY) revert MaxSupplyExceeded();
+ _mint(to, amount);
+ }
+
+ function burn(address from, uint256 amount) external onlyOwner {
+ _burn(from, amount);
+ }
+
+ function burn(uint256 amount) external {
+ _burn(msg.sender, amount);
+ }
+
+ function approve(address spender, uint256 amount) public override returns (bool) {
+ if (allowance(msg.sender, spender) > 0 && amount > 0) {
+ super.approve(spender, 0);
+ }
+ return super.approve(spender, amount);
+ }
+
+ error MaxSupplyExceeded();
+ error MintToZeroAddress();
+ }

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!