Algo Ssstablecoinsss

AI First Flight #2
Beginner FriendlyDeFi
EXP
View results
Submission Details
Impact: high
Likelihood: high
Invalid

Unrestricted Minter Assignment Allows Unauthorized DSC Minting

Root + Impact

Root Cause: The decentralized_stable_coin.vy exports the set_minter function from snekmate's ERC20 module, allowing the owner to add arbitrary addresses as authorized minters at any time.

Impact: If the owner account is compromised or acts maliciously, they can add any address as a minter and mint unlimited DSC without any collateral backing. This destroys the peg and results in total loss of funds for all DSC holders.

Description

Normal Behavior: Only the DSCEngine contract should be authorized to mint DSC tokens. This ensures all minted DSC is properly backed by collateral.

Issue: The decentralized_stable_coin.vy exports set_minter from snekmate's ERC20 module. The owner can add arbitrary addresses as minters, bypassing the collateral requirement entirel

# decentralized_stable_coin.vy
exports: (
erc20.IERC20,
erc20.IERC20Detailed,
erc20.burn_from,
erc20.mint,
erc20.set_minter, # @> Owner can add any address as minter
ow.owner,
ow.transfer_ownership,
)

Risk

Likelihood:HIGH

  • Reason 1 : Owner account is compromised (private key theft, phishing, social engineering)

  • Reason 2 : Malicious or compromised team member with owner access

Impact:

  • Impact 1 : Unlimited DSC minting without collateral backing

  • Impact 2 : Complete destruction of the peg and token value

Proof of Concept

An attacker who compromises the owner account calls set_minter(attacker_address, True) to grant themselves minting privileges. They then call mint(attacker_address, 1_000_000_000e18) to create 1 billion unbacked DSC. Finally, they sell this DSC on DEXs for WETH/WBTC, crashing the DSC price to zero and extracting all liquidity.

def test_owner_can_add_malicious_minter():
# Owner's private key is compromised
attacker = compromised_owner
# Step 1: Add attacker as minter
dsc.set_minter(attacker, True, sender=attacker)
# Step 2: Mint unlimited DSC
dsc.mint(attacker, 1_000_000_000e18, sender=attacker) # 1 billion DSC
# Step 3: Dump on market
# Attacker sells all DSC for WETH/WBTC
# DSC price crashes to $0
# All legitimate DSC holders lose everything

Recommended Mitigation

Remove the set_minter export entirely and set the DSCEngine as the only authorized minter during construction. This ensures the minting authority is immutably tied to the collateral-backed engine contract.

# decentralized_stable_coin.vy
+ DSC_ENGINE: public(immutable(address))
@deploy
- def __init__():
+ def __init__(dsc_engine: address):
+ assert dsc_engine != empty(address), "DSC__InvalidEngine"
ow.__init__()
erc20.__init__(NAME, SYMBOL, DECIMALS, NAME, EIP712_VERSOIN)
+ DSC_ENGINE = dsc_engine
+ erc20._set_minter(dsc_engine, True)
exports: (
erc20.IERC20,
erc20.IERC20Detailed,
erc20.burn_from,
erc20.mint,
- erc20.set_minter, # Remove this export entirely
ow.owner,
ow.transfer_ownership,
)
+ # If set_minter must remain, add strict validation
+ @external
+ def set_minter(minter: address, status: bool):
+ ow._check_owner()
+ # Only allow removing minters, never adding new ones after deployment
+ assert status == False, "DSC__CannotAddNewMinters"
+ erc20._set_minter(minter, status)
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge 3 days ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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

Give us feedback!