Compound and AAVE both have a bug that allows the entire protocol to be drained IF there's empty market open. Apparently, this has destroyed a large amount of forks.
Sonne was aware of this issue and had a mitigation strategy. First, add a timelock to add a market. Second, adds the funds. Finally, have the timelock open up the market for use. If followed in this order, it would be totally fine.
Sonne queued all of the multisig operations as seperate operations in the timelock. Since there was no order that had to be followed, this was a problem. Anybody could come execute these in any order they wanted.
The attacker executed the TWO timelock operations without adding funds in the middle of it. With this, the Compound/AAVE bug could be exploited once again, as before.
What should have been done better? Governance actions that must happen in a certain order must have restrictions on the ordering. For Open Zeppelin's timelock, scheduleBatch() can be used. Overall, interesting hack for 20M!