Exploit Disclosure - DXdao Governance

Overview

This proposal discloses a potential exploit that leverages a lack of front-end functionality reflection (on both Alchemy and DXvote) in the DAOstack contribution reward scheme (used for worker proposals). By using functionality available in the smart contract which is not reflected on the UI side, it’s possible to mint over 51% REP and take full control of DXdao.

Glossary

DXdao, an on-chain DAO since 2019
REP, the voting power in DXdao an ERC20 token without the transfer function (i.e. soulbound)
Alchemy, the original front-end UI for DAOstack smart contracts
DXvote, DXdao’s front-end UI for DAOstack smart contracts

Details

The Contributor Reward Scheme is the most used scheme at DXdao, it’s used for anything that transfers money including worker proposals, sponsorships, paying contractors etc. The scheme handles all fund transfers out of the DAO.

A couple of weeks ago, while both Alchemy and DXvote were down (most likely RPC issues), I decided to manually build a transaction and submit it. To do so, I had to dig into the scheme to see which parameters to set while building the transaction.

Looking at the scheme’s rewards array, I noticed all rewards (i.e. ETH, Stablecoins) are “requested per period”. Furthermore, there is a “Number of periods” argument that can be set when submitting a transaction manually.


In other words the scheme allows proposals to have redemption periods i.e. you can redeem a proposal more than once. A use case for this is a 3-month worker proposal which just has to be passed once, and subsequently is redeemable 3 times if the first and only proposal passes successfully. This functionality is also documented in the corresponding function of the Contributor Reward Scheme.

While this functionality is implemented on the smart contract, neither Alchemy nor DXvote (the only two front-ends to these smart contracts) display whether a proposal is a one-off proposal (as it is by default when submitting through DXvote or Alchemy) or if it has multiple periods (i.e. redeemable multiple times).

See this proposal: Alchemy | DAOstack

Looks normal, right?

However, if you look at the proposal creating txs, you can see this proposal actually has 5 periods.


This presents a severe vector of attack, if not monitored, as a proposal as innocuous as a Discord REP boost, could be submitted with enough redeem periods to effectively hold majority REP in the DAO. Additionally, it could also be used to redeem payments multiple times.

Attack Vector

The most pragmatic way to exploit this would have been through a Discord REP boost - which are REP issued to active members in DXdao’s Discord server. The REP boosts are issued quarterly - so all that would be required would be to join the DXdao discord server with a new anon account and being highly active in the DXdao server, to be included for a REP boost.

The lowest REP boost is 176.822 REP - sufficient to mint 51% REP. In the same proposal as above 0x8f0d1cb6d9497139e054162b1e067e91c6fe41cd1b8a51631eb62798c11aef89 Tenderly was used to overwrite 3 states:

  • Change REP minted to 176.822 (Discord boost amount)
  • Change Periods to 100’000
  • Simulate proposal to “passed” (to be able to simulate an execution)


The period essentially acts as a multiplier and mints 17M REP to the address. 17M REP would be 90% of all REP - giving the address the ability to instantly pass any proposal through majority votes (i.e. draining the whole treasury).


See Tenderly simulation: Tenderly Dashboard

At the time of the discovery of this exploit there were $84M the DAO, $37.8M of which in ETH and stablecoins.

Addressing the exploit

The exploit makes use of a simple mismatch between smart contract functionality and functionality reflected in the UIs. The only way to ensure such an attack never happens, is to actively monitor proposals for their periods.

The exploit was originally reported in June 2022 by @dlabs to @augustol @ross @johnkelleher and @powers - on the same day it was found. DXvote added monitoring for it in the development environment the same day.

DXvote will show a warning label on proposals as such:


And further detailed errors once the proposal is opened:


DXdao is also planning to fully migrate from DAOstack smart contracts to it’s own suite of contracts in the near future and has established a more robust monitoring process in the short term.

12 Likes

PR adding detection of the attack on the UI : Detect ContributionReward proposals with more than one period by AugustoL · Pull Request #913 · DXgovernance/dxvote · GitHub

Proof of existence of exploit submission to dxdao shared on chain (the 14 of August) on the transaction: Ethereum Transaction Hash (Txhash) Details | Etherscan

The input data of the transaction is the hash of a document sent by dalbs to dxdao explaining the exploit.

The hash shared is the SHA 256 hash of the document hosted in https://augustol.mypinata.cloud/ipfs/QmaGTLd9RhTTq8XvGCf4w1q93YJp8rjyjP1QAC63pSL35T

This way we prove the existence of that document by generating a unique and deterministic hash from it and sharing it on chain.

4 Likes

Great work guys!

LFG DAVI Team – we need our own governance system

1 Like

While DXvote already monitors for proposals using multiple periods, if monitoring is not deemed enough of a solution the contribution scheme could also be redeployed with one of the following changes:

  • Simply overwrite user input of _rewards array overriding rewards[3] with 0 and rewards[4] with 1 - at the smart contract level
  • Hardcode getPeriodsToPay function to only return 1 if the proposal is valid / passed
  • Ignoring the redeem periods param throughout the scheme

The more elegant solution is probably to remove periods completely, but due to the vast usage of it it’d take a lot more work. The solutions above are easy and quick fixes which should take less than 1H to do and deploy. The first option is probably safest?

1 Like

Can we get clarity on which contributors are responsible for this?

1 Like

Here is my timeline of events and a retrospective of my actions:

  • June 22: the vulnerability is reported by dave, that same day I make a pull request to detect the execution of the exploit on dxvote. We already had plans on moving away form Daostack contracts, so we decided to just fix the vulnerability when we do the migration since we were already monitoring on dxvote and other users were monitoring the proposals as well.
  • August 14: Dave had aBetween August 14 and Devconlready shared with us a document explaining the exploit and he wanted to publish it, we had a long discussion about it, I was strongly against publishing it before fixing the vulnerability on chain, what we had was a patch and monitoring in process, but the vulnerability still could be executed. To later verify the existence of the report I shared a hash of the pdf report on chain to later being able to verify the submission and in case someone else reported it dont get over Dave’s submission.
  • Between August 14 and Devcon I was very busy helping on the infinite hackathon and retreat organization, also working on governance 1.5 smart contracts and ERC20Guilds audit, during that time I had an accident snowboarding that ended up being pretty serious but I survived, then the restructure proposal and politics keep me even more occupied, and I ended up forgetting about the vulnerability Dave submitted.

Now looking back at the entire process, I can confirm I made mistakes (very stupid ones), like not realizing how easy was for this to be fixed and getting to it right away instead of waiting for the governance 1.5 migration, we should have done this in the first place.
But I still think that the vulnerability should not have been shared without having it entirely fixed, even more, if the reporter of the vulnerability is a member of the organization he is reporting the attack to.
In my opinion, with a bit more thought, patience, and communication we could have solved it quite easily. Like I did this morning, I created a PR with the changes to be done in the ContributionReward smart contract to fix it and already deployed a version of it on mainnet to be used.

As far as I understand when someone reports a white hack report it gives a deadline to the entity he is reporting to, when this deadline is reached the vulnerability is publicly disclosed by the reporter (I had no idea that the deadline was after Devcon), It would have been nice to be notified of it and have a more professional disclosure of this.
I assume part of the responsibility on the process, a process that was never clear in dxdao and now we have to work on it and improve it to don’t hurt the reputation of the dao on not honoring white hack submissions.

At last, regarding the reward amount, I do have not a strong opinion here, but I think we can use the critical vulnerability reward in our vaults on hats.

Next steps?

  • The github pull request should be reviewed by dxgov team.
  • If we accept the changes done in the contract, we can create a proposal to register this as a new scheme, test it and then remove the old ConributrionReward scheme.
3 Likes

Just to clarify, I did ask you as tech dev lead if it was ok to publish - and you gave the thumbs up.

Unfortunately, I disagree. IMO if I didn’t go public nothing would have ever been done - not even after the Gov 1.5 upgrade unless I would be there pushing for it. It also sucks to constantly have to beg people to talk about the vulnerability / do something. Feels like I’m begging for money.

Why wasn’t anything done in the past 5 months? From your PR to fix the issue it’s clearly a very simple fix and took at maximum a couple of hours of work.

I believe industry best practice is 90 days, and then release regardless of a fix in place or not. Source: Vulnerability Disclosure - OWASP Cheat Sheet Series

Again, if you didn’t give me the green light to publish I never would have done so - so trying to blame me for having published it with getting approval of DXdao tech dev lead seems a bit hypocritical.

Why I did it after Devcon is pretty simple. The Gov 1.5 contracts were planned to be operational before Devcon – which they weren’t – so it’s just a date I had in my mind.

1 Like

You asked me if you can publish it, and my answer was yes. Of course, you can! but I think you shouldn’t do it before submitting the fix on mainnet and I always said that since June 22, I always you told you that, go ahead and disclose it whenever you want, I cant stop you to do it, you don’t need my permission to disclose it. The communication here could have been better between us.

I explained the reasons on my previous post, where I acknowledge it was a mistake.

I dont see how I am blaming you for it, I am clearly assuming responsibility for how everything was done and expressing my opinion on how it could have been done better in my previous post.

Also, I just had a call with @dlabs and we talked about this.

I think we should move forward and focus on the fix on chain and arranging a proper reward for the exploit report.

3 Likes

The most significant thing is that Dave reported this in good faith to DXdao. The treasury is somewhat safe from this SE attack vector. The least the DXdao community can do is be grateful that Dave or anyone else hasn’t taken advantage of it to date.

As a close friend of Dave, I’ve been hearing about community suggestions about a fair reward. I’m aware of numbers ranging from $400 to $1m. The mean of those numbers could make sense as the bug is merely a result of a miscommunication between the UI (Alchemy) and the DAOstack contracts. Yet, given the immense amount of funds at risk and the fact that Dave is an FT contributor to DXdao, a 5% reward is fair. Bear in mind that the industry standard is 10% of the funds at risk.

5% seems a lot, so I invite the DXdao community to record their inputs, and then we take the median of those accounts. Ultimately, both REP and DXD holders are the final arbitrator.

3 Likes

Firstly an amazing find by Dave and very thankful for the disclosure! Just wanted to leave my thoughts on the bonus:

Having seen the Hats tiers, I personally think that using their guidelines, the next tier of $104k (without Hats’ cut! So 17% more to Dave than if it were paid via Hats), is where I’d land, for the following reasons:

While this could have resulted in severe loss of funds (although it is technically closer to $38M [ETH + stables + 0.5 * total liquidity for DXD & SWPR] rather than the $80M spot price of assets, given very small liquidity pools of DXD and SWPR!), it was not a smart contract issue but more a DXdao process issue/front-end issue.

Dave is a full time contributor, and the worker proposal for this period included QA testing DXvote. This isn’t to say that it was Dave’s fault the issue was present, nor that it was strictly within his job description to find it, but more that it seems to me that he had relevant business as part of his role to be in and around DXvote, its contracts, and front end where an external party reporting the vulnerability would not have been as part of their responsibilities; I think this should be reflected in some way. This is the main reason that I think the highest tier is not appropriate for this disclosure.

While it’s abundantly clear that this was a genuine find and there was absolutely zero malice involved, I would like to establish a framework whereby internal disclosures strike a balance between encouraging investigation such as Dave’s, while not introducing perverse incentives at the same time, as @Luigy mentioned in Discord. The reason there usually isn’t an internal bug bounty process for most organizations is that it could encourage vulnerabilities to be left in code by design. Therefore, it seems to follow that this kind of bonus would only really be available to non-devs internally, without allowing for these incentives to creep in. Is this a good thing? Does it create a divide? Just thinking out loud.

Finally, I would like to signal a strong belief that the bonus should be paid in stablecoins, regardless of the amount. I’m not sure whether the suggestion to ‘use Hats’ above was literal in all senses including the currency, but the DAO has made strong commitments not to make payments or utilize DXD while significantly under NAV to date, for obvious reasons, and I don’t think this should be an exception to that. Unless Dave wanted DXD priced at NAV, but I’m guessing he’d rather perfectly liquid USDC :stuck_out_tongue:

12 Likes

To start, a big warm THANK YOU and hug to Dave for discovering this issue in the system. This was a very big issue that existed and it was very important that it was found. So thank you Dave.

Some side learnings. Why was this not found earlier?
Alchemy front-end was ignoring it even though people within DAOstack clearly new about the field in the backend. Getting more info about this would be helpful learnings.

The main chance I would think this should have been discovered is when DXdao was creating DXvote, our new front-end. When making a full new front-end, for a set of contracts, it would seem quite appropriate to make sure all the back-end variables match up to the front-end variables, right?
So, if there are 10 back-end variables, then there should be 10 front-end variables.

When making DXvote, why was this situation not noticed? Were the number of back-end variables counted? I am unfamiliar with how the process happens, but it seems this matching exercise would be a very common tactic. Is this the case?

We have a unique situation. What happens when an internal non-dev finds a critical dev issue?

Is there precedence for something like this in the space? I personally have not heard of a situation like this. Has anyone else?

I tried to gather some info from other high profile Defi communities for comparison.

One community pays out ~$200k for critical bugs and has done so more than once. These were paid externally.

It was also very important to note that paying out internally is different than paying out externally. (However, keep in mind that a person could always report something anonymously, so that makes things tricky)

Another person noted that generally, “bounty systems are designed to be effective in an adversarial environment. Not applicable for internal use imo.”
However this person agreed that there should be some “gift” to this internal person because it was VERY important.

We are sitting in unfamiliar territory.

We have the Hats program we could reference. Why were these contracts not included in DXdao’s Hats program?

I would say that under Hats, one could consider this critical. In that case 80% of the Hats Vault would be paid. That’s a good reference point.

In this case, we can reference Hats without using Hats for the payout. So there is still the option to pay a bounty in a token that is not DXD from the hats Vault.
(However, this raises another good question. Do we want the DXdao Hats vault to be using DD or another token like DAI?)

I think Dave should receive a sizable gift from DXdao for finding this very important issue.

I also think that DXdao should clearly outline and explain the decision it makes, how it will prevent things like this in the future, express outwardly that DXdao will pay real money for bugs reported directly to DXdao safely, and the whole DXdao community should be reasonably ok with the final outcome.

(Disclosure: I have some DXD in Hats Vault. I would be ok with paying from Hats Vault or from outside of Hats Vault. Open to what the community wants.)

4 Likes

I think the appropriate framework to reward a contributor for excellence is to give them a bonus, which there is some precedent for with Retrospective Contributor Bonuses for Shipping. The highest level here was $20K (25% of that being DXD). For something so impactful as saving the treasury, then I think a multiple of this could be appropriate.

Using Hats as a frame of reference for amounts could make sense, but the Hats Vault, which is open for anyone to stake DXD, does not currently cover DXdao governance. Retroactively changing this and using the Hats vault to reward this finding would be inappropriate and a bad precedent to set. Level K has DXD staked in the Hats Vault, and the fact that discussions are being had about whether to use the vault to pay something that wasn’t covered by the vault makes me want for Level K to remove its stake.

2 Likes

My quick takes:

  • DXdao should pay a bonus/reward to Dave
  • Dave’s done a brilliant job and something outside his immediate scope
  • Exploits identified by contributors should be treated differently to those external to the DAO
  • No need to use Hats if governance wasn’t covered, especially considering they’ll be taking a cut
  • Reward should be in ETH/stables; immediate liquidity for Dave, and doesn’t undo the last X number of buybacks we’ve just done by paying out DXD below NAV

Each of these points have already been well articulated by others already so I’ll leave it at that. I do want to elaborate on one other point though which I think we need to establish as a clear precedent (and one I would think has always been the case but needs saying).

Contributors to a DAO have a fiduciary duty to the DAO.

“Fiduciaries should act in good faith in the interests of their beneficiaries, should impartially balance the conflicting interests of different beneficiaries, should avoid conflicts of interest and should not act for the benefit of themselves or a third party.”

DXdao is a DAO, not an LLC. Not suggesting we start applying corporate law suddenly. But fiduciary duty is an obvious positive in any org and should be expected from our contributors. That paid contributors will act in the interest of the DAO and it’s stakeholders. That should be affirmed here, as it seems to be missing from the conversation so far.

It wasn’t Dave’s responsibility to be looking for this exploit but once he found it, he had a fiduciary responsibility to report it; which he did. He did a bang up job and the DAO is clearly going choose to reward him for it.

The alternative is that while Dave did a great job finding the exploit and the right thing in reporting it, yet he had no more responsibility to report it to the DAO than an outside third party who hasn’t been claiming a salary. In which case we’ve established that contributors don’t owe a fiduciary duty to the DAO. Fortunately I don’t think anyone means to suggest that but if it were the case, we’d have fundamentally changed the dynamic between contributors and the DAO, and the value proposition offered by contributors is considerably lowered.

4 Likes

Any future grey/white hat seeing this thread will make their decision based on the outcome of this. Regardless if this is an internal/external incident we should reflect a good amount of reward for not going through an exploit. Thanks Dave for doing the right thing. Now it’s our turn doing so.

4 Likes

I was travelling and dealing with some stuff as all this was being posted so just thought I would chime in briefly to corroborate as I don’t have much extra to input.

I was in the same chats as Augusto when all of this was initially reported and Augusto’s timeline matches up with what I can verify. I was a little surprised to see the disclosure live already but understand the logic.
I don’t think to the best of my knowledge anything was said concretely about 1.5 contracts being live after devcon, in fact we only just got the preliminary audit report back DXgov Governance 1.5 Contracts Audit

Also just want to echo that as with many parts of DXdao we need some defined processes to better handle this in future.
Of course I support Dave getting a bonus for this amazing work!

2 Likes

Below is a brief poll to get some signal from the community, the poll can only be voted on by forum accounts with a trust level of at least 1.

Given the large makeup of DXD and SWPR of the Treasury this poll uses $38M as the total amount - which accounts for liquid assets in the treasury (mostly ETH and stables) at the time of the exploit.

Please cast your vote! (Poll is anonymous)

Exploit Reward - % based on $38M Total
  • 1,5% - $570’000
  • 1,25% - $475’000
  • 1% - $380’000
  • 0,9% - $342’000
  • 0,8% - $304’000
  • 0,7% - $266’000
  • 0,6% - $228’000
  • 0,5% - $190’000
  • 0,4% - $152,000
  • 0,3% - $114’000

0 voters

EDIT: DXD snapshot - DXD holders on Mainnet, Arbitrum and Gnosis Chain can vote. Based on feedback received so far, the categories are reduced to not have too many options. Snapshot

3 Likes

Big thanks to Dave for finding the disclosure and keeping tight for the past few months.

Stepping back, it would have been much easier to resolve the situation if there was a bug bounty process set up beforehand, rather than having to pick a reward amount and also set a precedent in one action - all through an informal governance process.

The key is to find comparable amounts in other projects and then adjust according to these specific circumstances. The Immunefi Board seems to be the best resource to compare.

I pulled a couple random ones here:

These are the maximum rewards and an estimated TVL of funds at stake in the respective systems. It’s tough to find an exact comparison but I think these help.

Given these existing bounties in the industry, I would venture to say DXdao would pay out a max 1% of its assets for the most severe vulnerability - typically major smart contract bugs. And so then the question is at what point on the spectrum is this vulnerability and then how is it discounted by the fact that Dave was/is a full-time contributor to DXdao?

3 Likes

I think there’s a HUGE difference between TVL and Treasury funds tbh.

Also most of these projects use Gnosis Safe as their Treasury - so not sure if it’s a fair comparison.

1 Like

I really don’t get the TVL to Bug Bounty amount in Immunefi as methodology. The amount of smart contracts covered by these projects is exhaustive, Makers $8.2Bn doesn’t sit in one smart contract - judging by the smart contracts they list on their Immunefi page its spread across over 120+ contracts.

Just looking at the projects you selected, so I have no bias in picking projects from Immunefi:

MakerDAO, Balancer, Alchemix, GMX, Optimism, Notional all state within their Rewards by Threat Level: “Critical smart contract vulnerabilities are capped at 10% of economic damage”.

OlympusDAO states: “For bugs/exploits which would lead to a loss of treasury funds, a reward amount equal to the potential loss of funds up to USD 3,333,333 (paid in OHM) is provided.’

So I just would like to say that if a severe vulnerability is found at DXdao - ignoring my own disclosure - I would be fully in support of paying 10% - which is clearly the industry standard. DXdao could perhaps vote on a maximum cap, similar to OlympusDAO.

I think signalling that in the event of a severe vulnerability, which would be the end of DXdao, we’d pay out 1% of a subset of assets is dangerous. It would be good if DXdao could pass an official ratified version on-chain so that we have an official resource voted on by the DAO.

2 Likes

I think the key that stood out to me here is the words smart contract, and maybe this hasn’t been emphasized enough by those advocating for an amount on the lower end of the ranges discussed (That said, I wouldn’t be vehemently opposed to the $256k figure mentioned elsewhere either). I think, while I don’t want to detract from the find, it is a lower severity (probability) issue than a smart contract exploit, due to necessity to be quite familiar with a lot of DXdao’s moving parts, community initiatives, and processes, to undertake.

I think this, as a percentage of their treasury, is fairly similar to the ranges being discussed right?

I think this is something that’d be great to have more DXD holders share their views on (Reminder to all, here! Snapshot vote for a temp check) - at the end of the day DXD holders are the ones that’d be the most financially at risk by any bad precedence set out here, so it’s a balancing act that would be good to gauge from their side. I’m really hoping more DXD holders will engage with the temp check before it closes.

1 Like