-
Notifications
You must be signed in to change notification settings - Fork 17
Add Secure Multisig Signing Process #122
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
base: develop
Are you sure you want to change the base?
Conversation
…ecurity-alliance#117) * Added prebuild.sh to vercel_build and updated Summaries. * Updating prebuild to work in vercel for dynamic summaries. * Updating wordlist as well for summaries * Updating wordlist
* Added prebuild.sh to vercel_build and updated Summaries. * Updating prebuild to work in vercel for dynamic summaries. * Updating wordlist as well for summaries * Updating wordlist * Updating prebuild config.
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
One thing people need to understand is that offline is not safer. Let me elaborate:
If you have a RATed device and you have simple clipboard hijack there, you will be faster "convinced" since they could let you copy the correct data while in my case you need to modify directly the script. The API approach is harder to really break it. Also, fyi, my tool is actively maintained and will add further features soon, e.g.
So, if you use forks, make sure they merge these features upstream or implement them differently. |
This does not go far back enough, it is only concerned with the actual ceramony which is not well defined. Multisig Best Practices
This appendix summarizes the best practices for the use of a 2-of-3
Policy for Transaction ValidationBest practice 3 prevents the co-signer from becoming merely a “deputy” acting on behalf ● A predetermined protocol for being asked to cosign (e.g., a half-signed transaction ● An allowlist of specific actions that can be performed by the wallet. ● A threshold for the number of transactions that can be executed on a given day, Best practice 4 mitigates the risk of a single stolen key. In a hypothetical example, an Duress / SafewordA voice call from the co-signer to the initiating signatory to confirm the transaction will reveal that the key has been stolen and that the transaction should not be co-signed. If under an active threat of violence, a “duress code” (code word, phrase, or other system agreed upon in
Warrant CannaryUsage of Warrant Canary is advised for escliated policy identification for duress levels.
Operational Safeguards
https://hackmd.io/@manifoldx/multisig-best-practices Additionally, a defined Incident Response plan in the case of compromise. ● Determine when the team will seek assistance from external parties (e.g., auditors, affected users, other protocol developers, etc.) and how it will onboard them. ○ Effective remediation of certain issues may require collaboration with external parties Defining Wallet Hygiene schedules, e.g. periodic revoking of all permissions |
Before the transaction proposer gives the first signature for the transaction, they should verify the signature using the [Cyfrin safe-tx-hashes tool](https://github.com/Cyfrin/safe-tx-hashes), which has a feature for verifying the first tx that [pcaversaccio's safe-tx-hashes-util tool](https://github.com/pcaversaccio/safe-tx-hashes-util) lacks. The feature generates a signature for transactions that have not been initialized, which is the case for this first transaction. More information exists in [the safe-tx-hashes documentation](https://github.com/Cyfrin/safe-tx-hashes?tab=readme-ov-file#not-initialized-transactions). Additional information about using the Cyfrin tool is found in [this Cyfrin Updraft tutorial video](https://updraft.cyfrin.io/courses/wallets/wallets/verify-multi-sig-signatures?lesson_format=video). An example command for using the tool to verify the first signature is with a command like: | ||
|
||
```bash | ||
./safe_hashes.sh --network base --address 0x86D46EcD553d25da0E3b96A9a1B442ac72fa9e9F --nonce 7 --untrusted |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Worth noting that there's a dependency on forge
here which makes forge
a massive target. It'd be valuable if safe_hashes
had an entirely independent implementation of the verification script and fuzzed the two against each other.
Some new ideas in relation to the human process if it helps or you can apply; Splitting Proposer and Signer responsibilities is an important mitigation.A number of Proposer keys should be added and solely sourced for proposals. It's preferable these "keys" are multiple hardware wallets but they could also be separate keys on a single hardware wallet. The keys can be held by a number of individuals or a single one. It's preferable the nature of this setup is held closely within the organisation. For the paranoid the proposal key could be an MPC key linked to it's own quorum and policy. Splitting proposers and signers has a number of benefits;
Safe Wallet Hacks need to be deep-dived and detections and mitigating controls adjustedByBit and WazirX were different on the Web2 side but near identical on the Web3 side. As a quick summary;
Deep diving each of these attacks meant you discontinued the use of blind signing devices, implemented an enterprise browser with specific controls, knew that you needed to independently generate and confirm Safe transactions and have a separate machine/iOS device to sign transactions. |
I'll try to respond to all the comments briefly. @pcaversaccio maybe you're right, I haven't thought as deeply about the different attack path for relying on the Safe API vs. offline mode. If you want to discuss on X instead of here, I added some comments today (but we can continue here if you prefer). No doubt what is written will change once the Safe API is back (perhaps in a modified form, only time can tell). @sambacha Thanks for sharing your best practices doc. I limited this PR to just the signing process. I have another list (still draft) of multisig best practices, but that will be a separate PR. tbh I haven't seen anyone using an allowlist of actions for their multisig, the closest I've seen is a description in plain English describing what each tx does, because I imagine updating the allowlist would be another separate process that must be done securely. @audityourcontracts I think these ideas would also mostly be a better fit into multisig best practices rather than adding to this secure signing process. I'll tag you when I make the other PR for best practices. I'm seeing more about warnings about using Safe operation 1 AKA delegatecalls (like the PR from @pcaversaccio) so I expect to add more details here soon to clarify what to do for deeper inspection of the delegatecall case (because using delegatecall to batch safe transactions is currently quite common). |
Cross-posting my reply: Let me rephrase: offline mode is helpful but doesn't mean it's safer by design. So what's the ultimate goal we want to achieve here? We want to detect if the transaction data sent to the Ledger itself is the one you intended to sign based on the information you see on the screen. One important part is the calldata as you say: let's say Safe is fully compromised, i.e. UI & API. You copy (via their copy button) the calldata from the Safe UI and want to verify it. In that step the copied data could switch as the UI is compromised remember, so you verify not the correct calldata. So you can be tricked into believing you verified the correct calldata. Since the Safe API is also compromised, you pull the data locally (let's assume the device is not compromised here). The data you will get is the malicious calldata BUT the benign decoded data to try tricking people into believing you see the correct decoded data. The calldata enters the local calculation of the hashes, so in order to match the message hash you see on the Ledger it must be the malicious one. But you need individually verify the decoded calldata always, and it doesn't matter via offline mode or Safe API mode. Since you got the calldata pulled via the Safe API (which must be malicious in this scenario), you can try to locally decode it yourself. If you use the version without the Safe API, in most of the times the people will use the UI to get the data from, which can be the wrong one. What I try to say is, offline is not bad at all, but how you get to the parameters you need for the offline mode can be risky.
It's important to say untrusted delegatecalls. You can find a list of all trusted delegatecallable contracts in my PR: pcaversaccio/safe-tx-hashes-util#14. |
I think it's easy to spend an inordinate amount of time theorycrafting the correct guidance for multisigs, especially if the end goal is to provide concrete, step-by-step guidance for a specific multi-sig implementation. I recommend trying to refactor this guidance to be as high level as possible. Talk about the different kinds of security controls that users need to think of, threat modeling, procedural considerations, monitoring. Ultimately there are going to be drastically different solutions in place to secure a $1B multisig vs. a $1m one, and each of those have different threat models and security budgets. If you really want to provide concrete guidance, make it clear that the guidance is specific for a certain user profile and that based on the amount stored, the system's requirements and controls should vary. There's still a lot of benefit in providing concrete guidance, but we also have to be honest about the limitations of one-size-fits-all guidance so high-tvl users know they will probably have to do more than the bare minimum. |
|
||
## Step 3: Transaction proposer prepares the first signature | ||
|
||
Before the transaction proposer gives the first signature for the transaction, they should verify the signature using the [Cyfrin safe-tx-hashes tool](https://github.com/Cyfrin/safe-tx-hashes), which has a feature for verifying the first tx that [pcaversaccio's safe-tx-hashes-util tool](https://github.com/pcaversaccio/safe-tx-hashes-util) lacks. The feature generates a signature for transactions that have not been initialized, which is the case for this first transaction. More information exists in [the safe-tx-hashes documentation](https://github.com/Cyfrin/safe-tx-hashes?tab=readme-ov-file#not-initialized-transactions). Additional information about using the Cyfrin tool is found in [this Cyfrin Updraft tutorial video](https://updraft.cyfrin.io/courses/wallets/wallets/verify-multi-sig-signatures?lesson_format=video). An example command for using the tool to verify the first signature is with a command like: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OpenZeppelin has also an ui for Safe transaction hash calculation for verification that could be worth to mention. It can be used through OZ hosted version https://safeutils.openzeppelin.com/ or running it locally https://github.com/openzeppelin/safe-utils
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the safe ui is using this instead of simulations via tenderly
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the safe ui is using this instead of simulations via tenderly
|
||
## Step 1: Connecting a hardware wallet | ||
|
||
Hardware wallets offer better security than most software wallets, so it's recommended that all multisig signer addresses are from hardware wallets. Multisig signing should ideally involve a direct connection of your hardware wallet with your browser. Avoid Metamask, Rabby, Frame, or other browser extension wallets as a middle man, as this increases the attack surface. However, this feature appears to have been removed recently after the ByBit hack so that a browser extension is required in this process. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that using the HW wallet through an injected wallet is inherently bad per se, it adds an extra layer of verification and setup diversity. However, its verification should be considered a confirmation of a valid transaction but NEVER a dismissal of a potentially malicious transaction
https://crypto-wallet-designed.github.io/crypto-key-calculator this computes the success rate of a wallet based on fault probabilities. |
40978af
to
443a2e9
Compare
I overhauled this draft and added a new markdown file outlining multisig best practices that aren't directly related to the multisig signing process. So now any suggestions or thoughts related to multisig security can be added to this PR, it just needs to be put into the proper place. @pcaversaccio I've switched the docs over to using your tool since I expect it will be better maintained going forward and I like the recent feature upgrades. I gave readers 2 options for verifying the first signature (which the transaction proposer should do). If you think it's better to give only 1 option, let me know if you think one is better to suggest. @audityourcontracts the proposer and signer focus on different steps in the signing process as documented (proposers do step 3, later signers do step 5). Do you think further info about this split should be written somewhere? @GianfrancoBazzani acknowledged, I removed the suggestion to use only a hardware wallet. I also added a link to the OZ Safe Utils website, but with a warning about the risks of trusting a 3rd party UI. @sambacha your link to https://crypto-wallet-designed.github.io/ is broken, is there a new link? @bsamuels453 If we assume the user profile is an average DeFi project, how would you alter the current docs for such users? |
I've been lurking, waiting for me to find a moment to intervene and help you with this whenever it is ready to be merged. Pay attention that I have been and will be pushing new updates and restructuring many things. For example, some modifications you suggested are to no longer existing pages or heavily modified ones (been updating many things these past days). This week, I'll start with Operational Security, so I suggest you continue as you are doing right now, focusing on a single page, the one we'll be able to add as a subsection to the Opsec framework. If you want to modify non-content-related code, like prebuild.sh scripts, create a separate PR to address that so I can keep track of it on a separate branch. And of course, thank you very much for taking an interest on frameworks, particularly in something like this. @fredriksvantes have you seen this? |
I have created an initial version of what a multisig SOP could look like. feel free to have a look at it and see if any of it could be of value to these documents: https://notes.ethereum.org/@fredrik/multisig-sop |
Thanks @fredriksvantes I pushed some ideas borrowed from the link you shared @mattaereal welcome to the thread, and thanks for leading this initiative 👍 This is my first PR here, feel free to lmk if I'm straying from the process |
@engn33r I think this is fine. I was specifically talking about separating proposers from signers using https://safe.mirror.xyz/GHmhFYhPS8gO3kManlQ8JrVUumr8gqfNkfhZifi5pUk I think we can publish a separate guidance for a more advanced / secure setup in the future. |
@mattaereal I don't have much more to add on this topic at the moment and I see less active discussion now. One option is to leave this open for other contributions or the other option would be to merge it as it is if you think it's ready. |
I was OOO and will be looking at this these next weeks. Thanks for all your work :) |
@engn33r can you merge develop into this, resolve any conflicts, if any, and then push changes? So I can actually compare and try to understand how to complement this with other pending upgrades I have on queue? |
This PR suggests recommended process steps for multisig signers to take in order to be informed about and have trust in the transaction they are signing (as opposed to blindly signing). This helps mitigate the risk of the Safe UI becoming a single point of failure (see the recent ByBit incident).
Comments are very welcome since this is a critically important topic.