Earlier this year, the GoodDollar protocol underwent a major security upgrade to correct a critical vulnerability discovered during work on a new set of contracts. The upgrade was a success and all functionality was fully restored within a short period, with enhanced safeguards.
As an added security measure, GoodDollar commissioned an audit of its staking contracts by ImmuneBytes, a security start-up that provides professional services on the blockchain.
Since transparency and community are central to all GoodDollar does, we wanted to share with you a brief account of the discovery and correction of the vulnerability, followed by a summary of results from the audit.
Discovery and Correction of the Vulnerability
(What follows is a first-person account from Technology Lead Hadar Rottenberg)
During work on our new Segmented UBI contracts, I discovered that the
initialize method in the
[ProxyFactory1967.sol](<https://github.com/GoodDollar/GoodProtocol/blob/4e5edbdc928485ea5c445aa041475e6e3ed72974/contracts/utils/ProxyFactory1967.sol#L14>)had no checks to prevent anyone from reinitializing the contract. Since it was clear that this was a critical bug, I immediately set out to address this.
The GoodDollar core team initially attempted to solve the problem by using a similar
initialize method in the proxy implementation with the same signature. However, because the proxy
delegate method only kicks in if the method is not implemented in the proxy, this fix was not successful.
After internal discussions, the core teem assessed the chief risks from the bug to be:
N.B. Staking funds in both TrustFund/Governance staking were NOT at risk at any time, as these are governed by immutable contracts.
The staking contracts are smart contracts that direct the Trust Fund to deposit the funds of stakers in third-party protocols such as Aave and Compound. They do not house any funds.
During the risk assessment, I also uncovered anomalies in the Donations contract. However, given the urgency of the situation, we decided to first concentrate our energies on the main risk: the USD $1M locked at the Reserve.
To ensure this was safe, I disabled the Governance contract controlling the DAO (Avatar) and immediately transferred all funds from the Reserve to the Avatar.
The Reserve contract still had permissions to mint G$s, however. To address this, I needed to upgrade and execute the code governing the
end method in the Reserve.
Risk mitigation was less complicated on Fuse, requiring me simply to disable governance and withdraw the funds from the UBI contract to the Avatar. I then upgraded the contracts in charge of GOOD and G$ Rewards to a version that would halt reward minting without preventing the withdrawal of staked funds.
The following day, the Reserve and the UBI contracts were restored in order to keep the protocol’s main functionality running. However, we decided to delay full replacement of the Reserve funds until we were fully confident the fix had been effective. These funds have now been fully restored.
Once the fix was in place, I turned my attention to the Donations contract. I found that my earlier concerns had been valid: an upgrade in the contract was needed to apply a proper
_onlyAvatar restriction on who could change where the funds would be staked. I further discovered that this bug had been exploited, costing the DAO $48K USD. This loophole has since been closed.
The Donations contract, deployed on mainnet, is a repository into which users can transfer donor funds in ETH or cDAI. These are then transferred into the staking contracts for deposit with third-party interest-bearing protocols.