Root Cause
UController.newOrganization(address avatar) is permissionless and blindly trusts the caller-supplied Avatar's nativeReputation() and nativeToken() getters with no verification that the returned Reputation contract is not already governed by another organization.
// Simplified vulnerable pattern in UController
function newOrganization(Avatar _avatar) public {
address rep = _avatar.nativeReputation(); // no ownership check
address token = _avatar.nativeToken();
// registers caller as a scheme with MINT rights on the returned rep contract
schemes[_avatar][msg.sender] = SchemePermissions.ALL;
rep.mintTokens(...);
}
An attacker deploys a shape-shifting fake Avatar that returns a decoy address on the first nativeReputation() call and the victim DAO's real Reputation contract address (0x625629...) on all subsequent calls. This tricks UController into granting the attacker full scheme permissions — including mintReputation — over the victim org's live Reputation token.
Attack Steps
| Step | Action | Detail |
|---|---|---|
| 1 | Deploy FakeAvatar | Returns dummy address first call; victim Reputation (0x625629...) on later calls |
| 2 | Call mintReputation(20000e18, attacker, fakeAvatar) | Inflates supply from 9,738.6 → 29,738.6 REP; attacker holds ~67% |
| 3 | proposeScheme + vote yes | Passes with attacker's freshly minted supermajority |
| 4 | sendEther(4.025e18, attacker, realAvatar) | Drains Genesis Alpha treasury in full |
Exploit block: 26,059,089 on Ethereum mainnet — entire attack executed in a single contract-creation constructor.
Impact
4.025 ETH drained from Genesis Alpha's treasury. While the absolute USD value is modest, the attack vector is a critical structural weakness in any DAO deploying the unpatched UController. The dormant DAOstack Genesis Alpha instance had zero defensive schemes registered, leaving newOrganization fully open.
Lessons for Auditors
- Permissionless factory functions that accept external contract references must verify ownership. Before granting scheme rights over a Reputation contract, assert that no other organization already governs it.
- Shape-shifting contracts bypass one-call checks. Callers that behave differently across invocations (storage toggling, constructor-vs-runtime logic) can defeat naive verification; read state from a neutral, known-good registry rather than the caller itself.
- Governance mint power equals treasury access. Any role that can
mintReputationis functionally an owner key — it deserves the same multisig or timelock guards as fund-moving roles. - Audit dormant protocol deployments. Legacy DAOs with unfrozen
UControllerand zero registered schemes are silently vulnerable; add a zero-scheme check to deployment checklists.