Algo Ssstablecoinsss

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

Permanent DSC Token Ownership and Minter Role Administrative Lock

Summary

During protocol deployment, ownership of decentralized_stable_coin.vy is transferred to dsc_engine.vy. However, dsc_engine.vy contains no functions to call set_minter or transfer_ownership on the DSC token. As a result, administrative control over the stablecoin is permanently locked inside the engine, preventing any future upgrades, minter role assignments, or governance interventions.

Vulnerability Details

In script/deploy_dsc.py:

# Lines 43-44
dsc.set_minter(dsce.address, True)
dsc.transfer_ownership(dsce.address)

The deployer configures dsc_engine as an authorized minter, and immediately surrenders ownership to dsce.address.
In src/decentralized_stable_coin.vy:

@external
def set_minter(minter: address, status: bool):
ownable._check_owner()
self.minters[minter] = status

Only the owner (which is now dsce.address) can invoke set_minter or transfer_ownership.
However, inspecting src/dsc_engine.vy reveals that no functions exist to interact with DSC's administrative functions:

  • There is no set_minter wrapper.

  • There is no transfer_ownership wrapper.

  • There is no arbitrary call or execution gateway.

Once deployed, no other entity (such as a governance DAO, a multisig treasury, a Peg Stability Module (PSM), or an upgraded V2 engine) can ever be granted minting rights. Furthermore, if dsc_engine is found to have a critical vulnerability, the stablecoin cannot be migrated to a patched contract without re-deploying a new token and completely abandoning the old token.

Impact

  • Architectural Deadlock: The protocol cannot perform system upgrades or migrate to a new engine.

  • Permanent Loss of Governance: The deployer and DAO permanently forfeit the ability to manage token permissions or add complementary modules (e.g. Flash Minting, PSM).

Proof of Concept

Verified in tests/unit/test_poc_audit.py::test_poc_permanent_dsc_ownership_lock:

def test_poc_permanent_dsc_ownership_lock():
dsc, dsce, _, _, _, _, _, _ = setup_audit_fixture()
assert dsc.owner() == dsce.address
# Non-owner cannot call set_minter
attacker = Account.create(999).address
with boa.env.prank(attacker):
with boa.reverts():
dsc.set_minter(attacker, True)
# dsc_engine has no method to call set_minter or transfer_dsc_ownership
assert not hasattr(dsce, "set_minter")
assert not hasattr(dsce, "transfer_dsc_ownership")

Tools Used

  • Moccasin v0.4.4

  • Titanoboa v0.2.8

  • Pytest

Recommended Mitigation

Do not transfer DSC ownership to the engine contract. Instead, retain DSC ownership in a multi-signature wallet or governance Timelock contract, and only grant the minter role to dsc_engine:

dsc.set_minter(dsce.address, True)
-dsc.transfer_ownership(dsce.address)
+dsc.transfer_ownership(governance_multisig_address)
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge about 2 hours 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!