Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replay Vulnerability in Governance Action Metadata #970

Open
Crypto2099 opened this issue Jan 22, 2025 · 19 comments
Open

Replay Vulnerability in Governance Action Metadata #970

Crypto2099 opened this issue Jan 22, 2025 · 19 comments

Comments

@Crypto2099
Copy link
Collaborator

I believe that all metadata standards, beginning from CIP-100 are currently vulnerable to replay attack because they do not contain a unique identifier field such as action: action1abc123. Because of this I could publish a new DRep ID but use a different individual's signed DRep metadata information in my own registration and there is no ability to "deny" that signature that is present in the metadata.

I will expand this issue with more examples and document potential solutions prior to moving towards solutions in all of the affect CIPs.

@Ryun1
Copy link
Collaborator

Ryun1 commented Jan 22, 2025

there is no ability to "deny" that signature

Is this not the purpose of the author's witness?
I think the first deny possibily against this, is for verifiers to not respect the same metadata multiple times - with the same witnesses

publish a new DRep ID but use a different individual's signed DRep metadata

Although I dont think anyone implements it
a counter for this would be to sign the metadata with DRep key, and then the verifier can check the metadata witnesses against the transaction witnesses
to ensure they apply to the same DRep

@Ryun1
Copy link
Collaborator

Ryun1 commented Jan 22, 2025

I think the first deny possibily against this, is for verifiers to not respect the same metadata multiple times - with the same witnesses

The problem here is, people submitting the same metadata by choice...
Say, with a DRep submitting a update certificate with the same metadata, to refresh their DRep activity

because there is no nonce, it means we cant guarantee uniqueness

@Ryun1
Copy link
Collaborator

Ryun1 commented Jan 22, 2025

Governance metadata has three main types

  • Governance action metadata
  • DRep metadata
  • Vote metadata

Metadata replays for governance action metadata, I feel couldn't be too damaging
The worst people could do is submit fraudulent actions which are imitating legitimate actions, voters should be able to discern this though.
It would be hard to choose a nonce for this.

DRep metadata, could be damaging and annoying to have fraudulent DReps
but signing metadata with DRep key and checking this against transaction witnesses, I feel could be a reasonable fix

Vote metadata, could be annoying
but again, checking the witnesses against the key which authorises the vote (DRep / CC Hot / SPO) is a reasonable fix

@gitmachtl
Copy link
Contributor

gitmachtl commented Jan 22, 2025

So why don't we simply take the author-name into account for the signature itself?

We generate a simple CBOR structure with the canonized body-hash like he have now, but also put in the author-name in a map-field. Than we sign the whole thing.

In that way you can't copy and paste the signature without also copying the author-name.

Checking against used keys in transactions makes it super complicated for tooling, not to get the whole needed data out of the metadata itself.

I don't fully understand the problem there might be in the first place. You can always copy&paste metadata information from someone else and sign it with your own keys.

If you wanna make sure that noone can impersonate another one, than you need a 2nd source of truth, like the drep-id in a social media account, etc.

@Crypto2099
Copy link
Collaborator Author

Governance metadata has three main types

  • Governance action metadata
  • DRep metadata
  • Vote metadata

I will refer to the last one as Rationale Metadata as that is potentially important. First and foremost the most key thing to understand is that we have an optional Authors block inside of the metadata itself that allows a known public key (does not necessarily need to match the credentials of the CC or DRep member themselves) to certify and ratify that they agree with certain things like:

  • Proposing a particular governance action on chain at a certain point in time
  • A DRep registering themselves as available for public delegation
  • A DRep or CC member casting their vote for a particular governance action and supplying rationale for their decision.

Metadata replays for governance action metadata, I feel couldn't be too damaging The worst people could do is submit fraudulent actions which are imitating legitimate actions, voters should be able to discern this though. It would be hard to choose a nonce for this.

Example 1: Replaying a Governance Action Metadata

While this may seem innocuous, let's take, for example the following scenario:

In March of 2025 Intersect submits and signs a Governance Action Proposal for a Treasury Withdrawal pursuant to a budget that was passed in February and they use some signing key to do so (probably not appropriate to use their CC member keys for this, so I imagine there will be some "other" PGP type of key that simply identifies the Intersect organization for the purposes of comms authentication). They propose that they should be allowed to withdraw 100,000 $ADA in order to facilitate the budget for 2025.

Yeah, Adam, that's what the metadata is there for, ya dummy! - Ryan (probably) [/jokes]

I hear you Ryan, however, I, as a malicious user intent on casting FUD against the budget process, commit my own governance action that actually withdraws 1M $ADA to an account under my control and I publish the exact same metadata, signed and certified by Intersect, as rationale for my proposal. Now, which one is "true" or authentic? You could say that you only take the first instance of that metadata into consideration or some other criteria or you could introduce some nonce (number used once) to ensure that anyone validating the metadata can clearly tell when it is being "replayed".

Potential Solution?

Perhaps a solution for replaying in this specific instance would be to repeat the withdrawals and amounts that are listed within the action itself which would help to "raise the red flag" against the fraudulent submission I have suggested.

DRep metadata, could be damaging and annoying to have fraudulent DReps but signing metadata with DRep key and checking this against transaction witnesses, I feel could be a reasonable fix

Example 2: Will the Real Ryan DRep Please Stand Up?

This is very similar to the "attack" above in that, I could identify a DRep that I dislike for whatever reason (they vote differently than me, they have more vote power than me, etc.). I can then create my own DRep ID but publish it using their metadata. Now, explorers show two different versions of the @Ryun1 DRep that vote in two completely different ways. Which one am I supposed to delegate to? Which one is the real one? Both of their metadata are signed by the key that is backed up by Ryan's GitHub and Twitter and Discord account... are they both Ryan? Is he becoming a multi-DRep to try and farm DRep rewards?! [/clutch pearls]

Potential Solution?

This attack is potentially the easiest to mitigate as we simply need to add a field into the body of the DRep metadata for the DRepId. Thus, the metadata is invalid/ineligible for any other DRep ID. Also, this allows the DRep to re-use the same metadata if they are merely publishing an update registration to toggle from inactive to active status. Thus, someone who is copying everything but your DRep ID still can't get an author signature from your (original/authentic) DRep ID.

Vote metadata, could be annoying but again, checking the witnesses against the key which authorizes the vote (DRep / CC Hot / SPO) is a reasonable fix

Example 3: Reusing Rationales

Again, as an example, the Cardano Atlantic Council uses a complex smart contract voting solution that does not allow us to simply and arbitrarily sign metadata w/ our CC credentials, so we have a separate credential that we use explicitly for this purpose and that key has now been published at our official rationale GitHub as a way to attest to its legitimacy.

Again the most likely attack vector here is from a malicious actor attempting to execute a public misinformation campaign against a well-known or public actor. And there are potentially two divergent "attacks" here when it comes to replaying a rationale.

Attack 1: CC as DRep

Even given a potential solution as simple as "Well, put the GovActionId into the body of the rationale" would allow a potentially malicious user to impersonate a CC member as a DRep by using the CC member's rationale files for their own votes as a DRep. By establishing a pattern of copying/cloning CC member votes as a public DRep, again, a misinformation or propaganda campaign against the CC member could be conducted attempting to frame them as also acting as a public DRep which they cannot controvert given that they have publicly signed both rationales. This creates FUD (fear, uncertainty, and doubt) about the potential CC member.

Reasons for this attack could be:

  1. Financial: if the attacker can gain a not insignificant amount of delegation by impersonating the CC member, particularly when/if DReps are compensated
  2. FUD: sow fear, uncertainty, and doubt about one or more members of the CC by impersonating them as DReps, potentially while at the same time starting to vote in ways opposed to the rationale file provided.

Attack 2: Disconnected from Intent

Finally someone could simply replay random rationale without a clear intent to besmirch any particular entity or individual but to randomly sow chaos into the system. The purpose of the "Authors" field w/i these various metadata was to allow for multiple authors to signal their intent, support, and alignment with a particular piece of rationale and/or justification for an on-chain action. It is important that we take steps to safeguard and protect the usefulness of this field and the information and signatures within by not allowing them to be arbitrarily used and reused against the wishes of the original signatories.

Potential Solution

Include not only a GovActionId in the rationale file which ties a rationale specifically to a particular governance action but also include a set of approved voter keys (VotingKeys) that may use this rationale (this allows for a rationale that is "co-signed" by a large number of disparate individuals who will use the same rationale to vote as a bloc).

In this way, the signature has explicitly agreed to those keys using this rationale but the signature is not valid if anyone else attempts to use the rationale.

@gitmachtl
Copy link
Contributor

gitmachtl commented Jan 22, 2025

Potential Solution?

This attack is potentially the easiest to mitigate as we simply need to add a field into the body of the DRep metadata for the DRepId. Thus, the metadata is invalid/ineligible for any other DRep ID. Also, this allows the DRep to re-use the same metadata if they are merely publishing an update registration to toggle from inactive to active status. Thus, someone who is copying everything but your DRep ID still can't get an author signature from your (original/authentic) DRep ID.

Actually we don't have to add a new field, we must just specify that one of the author signatures must be signed with the actuall drep secret key. We can simply verify that by hashing the publicKey and compare it to the drep-id that the metadata is posted to.

We can start with that right now and show dreps without signatures as meeeh, dreps with signatures that don't belong to the drep-id as naaahhh and dreps with at least a signature that is the drepkey itself as hurraayy.

@gitmachtl
Copy link
Contributor

Including the GovActionID into the metadata itself is extremly counterproductive to the workflow. Because for that we would need to precalculate the transaction hash which is than also the govactionid. But that changes every time we also change the GovActionID in the content. So the cat bites itself into the tail.

@gitmachtl
Copy link
Contributor

gitmachtl commented Jan 22, 2025

Another indicator for Action-Metadata to make it most unlikely someone abuses it would be to include the ActionDeposit-ReturnStakeAddress within a Action-Metadata body. This would directly mark an action proposal as false if the indicated StakeAddress is different from the one that is actually used in the proposal. Someone would really risk to loose 100kAda by reusing the StakeAddress of someone else, at the time of sending the proposal the 100kAda would be lost. Its a nice indicator, because it does not depend on any other hashes, slots or action-ids. An additional step would be to force that there must be a signature also with this stake-key.

@Quantumplation
Copy link
Contributor

I agree that this is an issue with the governance metadata standard. Apologies for not catching it when initially drafting things.

I think the most viable and reusable solution would be to add a nonce_tx_in field to the governance metadata, and require that that tx_in get spent when publishing the metadata. This is applicable to all different metadata types, and makes them one-time-use.

@Quantumplation
Copy link
Contributor

@gitmachtl is the GovActionId not the hash of the governance action itself (i.e. the type and properties of the governance action), rather than the full transaction hash?

@gitmachtl
Copy link
Contributor

@gitmachtl is the GovActionId not the hash of the governance action itself (i.e. the type and properties of the governance action), rather than the full transaction hash?

its the transaction hash or the outgoing utxo if you like.

@gitmachtl
Copy link
Contributor

I agree that this is an issue with the governance metadata standard. Apologies for not catching it when initially drafting things.

I think the most viable and reusable solution would be to add a nonce_tx_in field to the governance metadata, and require that that tx_in get spent when publishing the metadata. This is applicable to all different metadata types, and makes them one-time-use.

sounds a bit complicated to me especially when you wanna check and prepare in offline mode. also if you need more than one tx_in for the transaction. than you would need an array of tx_ins?

@Quantumplation
Copy link
Contributor

Quantumplation commented Jan 30, 2025

@gitmachtl is the GovActionId not the hash of the governance action itself (i.e. the type and properties of the governance action), rather than the full transaction hash?

its the transaction hash or the outgoing utxo if you like.

That's unfortunate :/ It might impact cosponsor's design.

I agree that this is an issue with the governance metadata standard. Apologies for not catching it when initially drafting things.
I think the most viable and reusable solution would be to add a nonce_tx_in field to the governance metadata, and require that that tx_in get spent when publishing the metadata. This is applicable to all different metadata types, and makes them one-time-use.

sounds a bit complicated to me especially when you wanna check and prepare in offline mode. also if you need more than one tx_in for the transaction. than you would need an array of tx_ins?

No, it could still be a single tx_in; i.e. the transaction inputs don't have to exactly match, they just have to include the specified tx_in as an effective nonce. I don't think it dramatically complicates the offline mode process; you just have to come into it knowing a txIn that you intend to spend.

Another approach would just be to include a nonce field that has to be unique per published document, but that imposes a requirement on indexers to keep track of all nonces, whereas the tx_in is stateless.

@Crypto2099
Copy link
Collaborator Author

Agree w/ both Martin and Pi that there's not a really good solution in the case of gov action proposals because of added burden and not an easily identifiable global "nonce" value to use. What about having something like a valid_until or valid_before field which uses an absolute on-chain slot number? This would allow it to at least easily "expire" the metadata?

@gitmachtl
Copy link
Contributor

gitmachtl commented Jan 31, 2025

We can put such a slotnumber inside the body content, but an imposer could again just reuse it 1:1 as an own metadata file during the action period.

But, what if we just make the DepositReturnAddress a part of the content that is signed?

I think it would be pretty rare to accept to loose 100k on an action trying to impose someone else. The social outcall would be big enough that such an action would never pass imo. It is time independent so metadata can be prepared in advance, uploaded, etc.. before.

But for that to work, we would need to change the CIP100 and its childs that such a "DepositReturnAddress" field within the Body-Content is a must.

Also we need to enforce that action metadata must be signed by at least one author.

That could work "ok" for action metadata imo.

@Crypto2099
Copy link
Collaborator Author

Small point of order but most of these changes should actually/probably be made to CIP-108+ because there is where we specifically specify what fields are required for: actions, registrations, and rationales. I don't know/think there's anything that we can explicitly add to CIP-100 to address these vulnerabilities and no one is ever submitting "just CIP-100" data and none of the solutions above are universal to every metadata type.

@Quantumplation
Copy link
Contributor

After thinking about it more, I actually really think the best way to address this would be to define a new set of fields (in a new CIP) focused on different ways of preventing replay attacks, and encourage tool authors to adopt those standards (include one when producing metadata on the write end, and display a warning when none of those fields are present or are incorrect, on the read end).

At the end of the day, we have to deal with any metadata that is out there in the wild, whether it has these fields or not; Including it in CIP-100 doesn't do anything to go out and force people to "update" their CIP-100 support, for example.

In part, maybe this is a reminder that tools should be treating this data as "supportive" rather than "authoritative" anyway: it should be clear to the user that the only thing that matters is what's on chain, and that this is provided to augment that.

To make it discoverable for future builders, we can mention it in CIP-100, and apply social pressure to make sure people implement it. There's a section explicitly for best practices and how to extend the CIP for exactly these reasons, and the ecosystem is new enough that it's likely manageable to do.

This also means we don't have to come up with the "best" solution right away; we can define what works, today, and adopt it in the places where it's being used, and evolve our approach over time with new strategies as we think of them or discover weaknesses, etc.

@Crypto2099
Copy link
Collaborator Author

This may make sense actually, as a separate CIP. "Governance Metadata Security Fields" or something similar (the same way we define different types of references). This could create a new "class" of object that can be defined, refined, and iterated on over time as we add additional governance actions, metadata, etc.

@rphair
Copy link
Collaborator

rphair commented Feb 5, 2025

@Crypto2099 @Ryun1 @gitmachtl @Quantumplation great points so far. My understanding from this more recently submitted issue:

... is that it continues the above discussion with a practical goal of producing a new CIP as suggested directly above.

Are there any cases where these proposed security fields for CIP-0108 would provide benefits other than preventing impersonation? If not, I would recommend closing this issue to avoid fragmenting the discussion, and also to include both issues in the Discussions: metadata for any CIP that results.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants