Calculated from recorded token losses using historical USD prices at the incident time.
0x5a6ebeb61a80b2a2a5e0b4d893d731358d888583Ethereum0x6e36556B3ee5Aa28Def2a8EC3DAe30eC2B208739EthereumAn unprivileged adversary cluster on Ethereum mainnet exploited BUILD Governance and the BUILD token to seize mint authority and extract ETH profit. Using only public governance functions on Governance contract 0x5a6e...8583, the cluster created and passed proposal 7 whose calldata called BUILD.setGovernance(attackerEOA). After proposal 7 reached the executable state, attacker EOA 0xdcc8a38a3a1f4ef4d0b4984dcbb31627d0952c28 executed it, causing BUILD token contract 0x6e36...8739 to set its governance variable to this EOA.
Once governance was captured, the attacker used the now-privileged EOA to call BUILD.mint multiple times, creating large amounts of BUILD from nothing, then routed portions of the minted BUILD through 1inch and related DeFi infrastructure into WETH and native ETH. Balance diffs across the mint, swap, and withdraw transactions show the attacker’s native ETH balance increased by exactly 4.599762619888583463 ETH after gas over the attack window. The core root cause is that Governance’s execute function can arbitrarily reassign BUILD.governance, and BUILD’s mint and setGovernance functions enforce only require(msg.sender == governance) with no restriction that governance remain a neutral contract or that minting be capped, enabling an ACT-style anyone-can-take governance-capture and unlimited-mint exploit.
0xff2cf5ec92983daf075967b5652a8682419e882bf447d8da4d222118bfd94fba0xc42f7af9ae94f6c5f480202c4bb268a24341d6cbe3aa0323eb4a99b0321c3fcd0x648ea1548c20542d9545b329f9c1b5f5265a0ec71686caa944376213bdb0327b0xc34c8a55776f9a02be163b5bcd52c21ac08df2c1da97f0f13e5618c7645266890x3a9868b67f3e2ec90a5e9d5fce9a8176dfd8189b2cc37a2ed8cd8e5016c74955BUILD Governance (0x5a6e...8583) is a token-locking governance system. Users lock a voting token to gain voting power, must meet proposalThreshold to create proposals, and proposals must accumulate quorumVotes in favor to pass. Once a proposal reaches the appropriate state, Governance exposes an execute(uint256,address,uint256,bytes) function that can call an arbitrary target contract with arbitrary calldata. There is no on-chain allowlist or guardrail limiting which contracts or functions can be invoked via execute.
The BUILD token (0x6e36...8739) is an ERC20 with a single governance address that fully controls minting and further delegation of this power. The critical functions are:
contract BUILD is ERC20, ERC20Detailed {
using SafeERC20 for IERC20;
using Address for address;
using SafeMath for uint;
address public governance;
constructor () public ERC20Detailed("BUILD Finance", "BUILD", 18) {
governance = msg.sender;
}
function mint(address account, uint amount) public {
require(msg.sender == governance, "!governance");
_mint(account, amount);
}
function setGovernance(address _governance) public {
require(msg.sender == governance, "!governance");
governance = _governance;
}
}
In the intended design, Governance is the contract that should hold the governance role on BUILD, so that BUILD minting decisions go through on-chain proposals and voting. However, nothing in BUILD enforces that governance remain a contract, or that it not be set to an EOA capable of minting directly for its own benefit. Nothing in Governance enforces that execute cannot be used to call BUILD.setGovernance to assign governance to an arbitrary address.
The adversary uses standard DeFi components to realize profit: a DSProxy instance to interact with Balancer-style pools, and 1inch AggregationRouterV4 to swap minted BUILD into WETH and then unwrap WETH to ETH. All of these components are permissionless and accessible to any EOA.
The vulnerability is an overpowered governance execute combined with unguarded governance role on the token, which collapses the intended separation between a neutral governance contract and profit-seeking EOAs. On the BUILD token, mint and setGovernance are both gated solely by require(msg.sender == governance) with no additional constraints. On the Governance contract, execute allows any passed proposal to call an arbitrary target with arbitrary calldata once its state indicates readiness for execution.
This combination means an adversary that accumulates enough voting power to pass a single proposal can schedule a call to BUILD.setGovernance(attackerEOA), then execute it to move BUILD.governance from Governance to their own EOA. Once that invariant is broken, the EOA can call BUILD.mint in a permissionless way, creating arbitrary BUILD supply and routing it through DEXes for ETH. The protocol never enforces that governance remain a contract, never restricts the set of callable functions via execute, and never caps minting. The root cause is thus a governance-takeover enabling unlimited minting, fully realizable under an ACT adversary model because all steps rely only on public governance rules, public contract code, and permissionless DeFi interactions.
The critical invariant is:
For all times t, increases in
BUILD.totalSupplymust be authorized exclusively by a neutral governance contract that cannot directly mint BUILD for its own unilateral profit; equivalently, theBUILD.governancestorage slot must never be set to an EOA that can arbitragemint()for personal gain.
The concrete breakpoint operation is:
In transaction
0x544e5849b71b98393f41d641683586d0b519c46a2eeac9bcb351917f40258a85at block14182038, attacker EOA0xdcc8...callsGovernance.execute(7, BUILD, 0, data), wheredataencodesBUILD.setGovernance(0xdcc8...). The call pathGovernance.execute -> BUILD.setGovernanceupdates theBUILD.governancestorage slot from the Governance contract address to0xdcc8..., violating the invariant.
The seed transaction trace for this tx confirms that Governance is the entrypoint and that a call into BUILD is executed with calldata corresponding to setGovernance:
Seed transaction trace (cast run -vvvvv) for tx 0x544e...:
SM Address: 0x5a6ebeb61a80b2a2a5e0b4d893d731358d888583, caller:0xdcc8a38a3a1f4ef4d0b4984dcbb31627d0952c28
...
; Governance.execute(7, BUILD, 0, data) decodes and initiates an external call to BUILD
...
; downstream call targets BUILD 0x6e36...8739 with function selector matching setGovernance(address)
From this point onward, require(msg.sender == governance) on BUILD accepts 0xdcc8..., granting the attacker unrestricted access to mint and the ability to reassign governance again if desired.
On the Governance contract (0x5a6e...8583):
votingPeriod, executionPeriod, quorumVotes, and proposalThreshold are static numerical parameters controlling the lifecycle of proposals.target, value, and data. Once a proposal passes and reaches a ready-to-execute state, anyone can call execute(id, target, value, data) to perform the call.target or data; any contract and function can be invoked, including those that assign or escalate privileges.On the BUILD token (0x6e36...8739):
governance is initialized to the deployment caller (in practice, the Governance contract).mint(address,uint256) mints arbitrary amounts to any account so long as msg.sender == governance.setGovernance(address) reassigns governance to any _governance if called by the current governance.The protocol assumes that Governance will always be the owner of governance on BUILD, but this is not enforced. There is no require that governance be a contract, nor any safeguard against proposals that reassign governance to an EOA.
Governance txlists and traces around proposal 7 show the following sequence:
0xd6dbed... approves BUILD to Governance and submits proposal 7 targeting BUILD with calldata encoding setGovernance(0xdcc8...).forVotes exceed againstVotes and meet quorumVotes, moving the proposal into the state where it can be executed.0x544e... at block 14182038, EOA 0xdcc8... calls Governance.execute(7, BUILD, 0, data). The seed trace confirms the external call from Governance into BUILD with setGovernance(0xdcc8...), and storage diffs around the BUILD governance slot show a change from the Governance address to 0xdcc8....Once BUILD.governance equals 0xdcc8..., the attacker submits three mint transactions:
0xe6f47156c24c7628b93c5abc0d663dc337e976781778aa6f630aa327977b4e60 (block 14182042, mechanism mint)0xff2cf5ec92983daf075967b5652a8682419e882bf447d8da4d222118bfd94fba (block 14182048, mechanism mint)0xc42f7af9ae94f6c5f480202c4bb268a24341d6cbe3aa0323eb4a99b0321c3fcd (block 14182054, mechanism mint)Balance diffs for these txs show the BUILD token being created directly to the attacker:
// Example: tx 0xe6f4... (first mint)
{
"erc20_balance_deltas": [
{
"token": "0x6e36556b3ee5aa28def2a8ec3dae30ec2b208739",
"holder": "0xdcc8a38a3a1f4ef4d0b4984dcbb31627d0952c28",
"before": "0",
"after": "100000000000000000000000",
"delta": "100000000000000000000000",
"contract_name": "BUILD"
}
]
}
The other two mint transactions similarly show large positive BUILD deltas to 0xdcc8... (7,600 BUILD and 1,000,000 BUILD-equivalent amounts), with only small negative ETH deltas corresponding to gas costs. There is no incoming token spend from the attacker; BUILD appears from the zero address via mint.
After minting, the attacker converts BUILD into WETH/ETH via DeFi infrastructure:
0x648ea1548c20542d9545b329f9c1b5f5265a0ec71686caa944376213bdb0327b (block 14182050, mechanism swap via 1inch)0xc34c8a55776f9a02be163b5bcd52c21ac08df2c1da97f0f13e5618c764526689 (block 14188829, mechanism swap via 1inch)0x3a9868b67f3e2ec90a5e9d5fce9a8176dfd8189b2cc37a2ed8cd8e5016c74955 (block 14188842, mechanism withdraw via WETH)The balance diffs for these txs show ETH inflows and BUILD outflows from the attacker:
// Example: tx 0x648e... (1inch swap)
{
"native_balance_deltas": [
{
"address": "0xdcc8a38a3a1f4ef4d0b4984dcbb31627d0952c28",
"before_wei": "353676727661241689",
"after_wei": "4831548861904691557",
"delta_wei": "4477872134243449868"
}
],
"erc20_balance_deltas": [
{
"token": "0x6e36556b3ee5aa28def2a8ec3dae30ec2b208739",
"holder": "0xdcc8a38a3a1f4ef4d0b4984dcbb31627d0952c28",
"before": "7600000000000000000000",
"after": "0",
"delta": "-7600000000000000000000",
"contract_name": "BUILD"
}
]
}
// Example: tx 0x3a98... (WETH.withdraw)
{
"native_balance_deltas": [
{
"address": "0xdcc8a38a3a1f4ef4d0b4984dcbb31627d0952c28",
"before_wei": "745679340714433351",
"after_wei": "897716860263569111",
"delta_wei": "152037519549135760"
}
]
}
Summing positive ETH deltas to 0xdcc8... across the swap/withdraw leg and subtracting the gas costs measured in the relevant mint/swap/withdraw txs yields a net ETH profit of 4.599762619888583463 ETH over the attack window. This net delta is encoded directly in the success predicate of root_cause.json and does not rely on estimated prices or off-chain data.
The exploit therefore consists of:
governance to an EOA.All steps are permissionless and reproducible by any adversary that controls sufficient BUILD voting power to pass the governance proposal.
The adversary-related cluster accounts are:
Governance.execute(7, ...) in tx 0x544e....0xe6f4..., 0xff2c..., and 0xc42f....4.599762619888583463 ETH in native balance after gas.BUILD.setGovernance(0xdcc8...).0xdcc8..., supporting classification as a cooperating governance/trading address.0xdcc8....execute(address,bytes), so its interactions with Balancer and DEX pools are under attacker control.Governance priming and proposal creation
0xf8990741e0195b3616b0b1f422f59b405c2b655109f6ed05fa90e9b4738c48d1 (block 14169189, mechanism approve): the adversary cluster approves BUILD to Governance, enabling token lock and voting.0xfa9cca40f225745c2eac97521d979ddfa4edae589ff0f1b543b94345e52335e9 (block 14169198, mechanism governance_propose): proposal 7 is created with target BUILD and calldata encoding setGovernance(0xdcc8...).0x9b116ef389e12c6ccb99fedd9f6dd881ea6a893d8d4a890928be45839932e024 and 0xb6edc1f0b5b2558aae3d886c1d52c15e0126021c91f052e0378ee707f6e85be8 (blocks 14169204 and 14182045, mechanisms governance_vote): adversary EOAs vote so that forVotes exceed againstVotes and meet quorumVotes, moving proposal 7 to a ready-to-execute state.Governance execution and mint authority capture
0x544e5849b71b98393f41d641683586d0b519c46a2eeac9bcb351917f40258a85 (block 14182038, mechanism governance_execute):
0xdcc8... calls Governance.execute(7, BUILD, 0, data).BUILD.setGovernance(0xdcc8...).BUILD.governance storage slot is updated from 0x5a6e...8583 (Governance) to 0xdcc8....mint and setGovernance functions accept 0xdcc8... as msg.sender.Unlimited minting and ETH extraction
0xe6f4... (block 14182042, mechanism mint): BUILD.mint mints 100,000 BUILD-equivalent units directly to 0xdcc8..., as shown by a +100,000 BUILD delta in the balance diff, with only gas cost in ETH.0xff2c... (block 14182048, mechanism mint): BUILD.mint mints 7,600 BUILD directly to 0xdcc8....0xc42f... (block 14182054, mechanism mint): BUILD.mint mints approximately 1,000,000 BUILD-equivalent units to 0xdcc8....0x648e... (block 14182050, mechanism swap): the attacker uses 1inch to swap 7,600 BUILD for ETH, with the balance diff showing a large positive ETH delta at 0xdcc8... and a full depletion of the 7,600 BUILD.0xc34c... (block 14188829, mechanism swap): the attacker uses 1inch unoswap to route a ~ BUILD chunk through liquidity pools; balance diffs show large negative BUILD deltas from into pools and relatively small ETH gas costs.Over these mint, swap, and withdraw transactions, the summed ETH inflows to 0xdcc8... minus gas outflows equal a net profit of 4.599762619888583463 ETH. No privileged roles, whitelists, or private channels are used; the only prerequisite is sufficient BUILD voting power to pass proposal 7 under the public Governance rules.
The directly evidenced financial impact on-chain is:
4.599762619888583463 ETH of net profit realized by attacker EOA 0xdcc8a38a3a1f4ef4d0b4984dcbb31627d0952c28 over the core attack-leg transactions, after accounting for gas costs.Beyond the ETH-denominated profit, the exploit causes unbounded inflation of BUILD supply under attacker control:
1,107,600 BUILD units directly minted to 0xdcc8... across the documented mint transactions.These effects degrade the integrity of BUILD Governance and the BUILD token:
governance.Contracts
0x5a6ebeb61a80b2a2a5e0b4d893d731358d888583) – source code as collected in artifacts/root_cause/data_collector/iter_1/contract/1/0x5a6e...8583/source/src/Contract.sol. Used to confirm proposal lifecycle, voting thresholds, and the behavior of execute(uint256,address,uint256,bytes).0x6e36556B3ee5Aa28Def2a8EC3DAe30eC2B208739) – source code as collected in artifacts/root_cause/data_collector/iter_1/contract/1/0x6e36...8739/source/src/Contract.sol. Used to confirm governance storage, and the implementations of mint and setGovernance.Key transactions
0xf8990741e0195b3616b0b1f422f59b405c2b655109f6ed05fa90e9b4738c48d1 – BUILD approval to Governance (governance priming).0xfa9cca40f225745c2eac97521d979ddfa4edae589ff0f1b543b94345e52335e9 – proposal 7 creation (BUILD.setGovernance(0xdcc8...)).0x9b116ef389e12c6ccb99fedd9f6dd881ea6a893d8d4a890928be45839932e024 and 0xb6edc1f0b5b2558aae3d886c1d52c15e0126021c91f052e0378ee707f6e85be8 – governance votes for proposal 7.0x544e5849b71b98393f41d641683586d0b519c46a2eeac9bcb351917f40258a85 – Governance execution of proposal 7, calling BUILD.setGovernance(0xdcc8...).0xe6f47156c24c7628b93c5abc0d663dc337e976781778aa6f630aa327977b4e60 – first BUILD.mint to attacker (100,000 BUILD-equivalent).0xff2cf5ec92983daf075967b5652a8682419e882bf447d8da4d222118bfd94fba – second BUILD.mint to attacker (7,600 BUILD).0xc42f7af9ae94f6c5f480202c4bb268a24341d6cbe3aa0323eb4a99b0321c3fcd – third BUILD.mint to attacker (~1,000,000 BUILD-equivalent).0x648ea1548c20542d9545b329f9c1b5f5265a0ec71686caa944376213bdb0327b – 1inch swap converting 7,600 BUILD into ETH.0xc34c8a55776f9a02be163b5bcd52c21ac08df2c1da97f0f13e5618c764526689 – 1inch unoswap routing a ~1e24 BUILD chunk through liquidity pools.0x3a9868b67f3e2ec90a5e9d5fce9a8176dfd8189b2cc37a2ed8cd8e5016c74955 – WETH.withdraw converting WETH into 0.152037519549135760 ETH at the attacker EOA.Traces and balance diffs
0x544e... – artifacts/root_cause/seed/1/0x544e5849b71b98393f41d641683586d0b519c46a2eeac9bcb351917f40258a85/trace.cast.log. Confirms the call path Governance.execute -> BUILD.setGovernance and the update of the governance slot.artifacts/root_cause/data_collector/iter_2/tx/1/0xe6f4.../balance_diff.json, 0xff2c.../balance_diff.json, 0xc42f.../balance_diff.json. Used to verify BUILD supply creation and ETH gas costs.artifacts/root_cause/data_collector/iter_3/tx/1/0x648e.../balance_diff.json, 0xc34c.../balance_diff.json, 0x3a98.../balance_diff.json. Used to compute the net +4.599762619888583463 ETH change in the attacker’s native balance.Txlists and address-level context
0xd6dbed... and 0xdcc8... – collected under the artifacts/root_cause/data_collector/iter_3/address/... directory, providing context for governance participation, DSProxy deployment, and value transfers between the adversary addresses.1e240xdcc8...0x3a98... (block 14188842, mechanism withdraw): the attacker calls WETH.withdraw, converting WETH into 0.152037519549135760 ETH at 0xdcc8..., as recorded in the native balance diff.