From 7bfce67623f6a8fdd875062581d20e7dca7578ae Mon Sep 17 00:00:00 2001 From: Isaac Patka Date: Mon, 6 Apr 2026 11:35:57 -0400 Subject: [PATCH] Rev multisig guidance with new attacks, concerns. add a key takeways page for quick reference and linking --- docs/pages/multisig-for-protocols/index.mdx | 1 + .../joining-a-multisig.mdx | 13 +- .../multisig-for-protocols/key-takeaways.mdx | 115 ++++++++++++++++++ .../pages/multisig-for-protocols/overview.mdx | 5 + .../planning-and-classification.mdx | 21 ++++ .../registration-and-documentation.mdx | 11 ++ .../setup-and-configuration.mdx | 27 +++- .../use-case-specific-requirements.mdx | 104 +++++++++++++++- .../secure-multisig-best-practices.mdx | 76 +++++++++++- .../secure-multisig-safe-verification.mdx | 49 +++++++- .../secure-multisig-squads-verification.mdx | 17 +++ utils/fetched-tags.json | 58 +++++---- vocs.config.tsx | 1 + 13 files changed, 453 insertions(+), 45 deletions(-) create mode 100644 docs/pages/multisig-for-protocols/key-takeaways.mdx diff --git a/docs/pages/multisig-for-protocols/index.mdx b/docs/pages/multisig-for-protocols/index.mdx index c99231d9..89d850d0 100644 --- a/docs/pages/multisig-for-protocols/index.mdx +++ b/docs/pages/multisig-for-protocols/index.mdx @@ -12,6 +12,7 @@ title: "Multisig For Protocols" ## Pages - [Multisig Security Framework](/multisig-for-protocols/overview) +- [Multisig Key Takeaways](/multisig-for-protocols/key-takeaways) - [Multisig Planning & Classification](/multisig-for-protocols/planning-and-classification) - [Multisig Setup & Configuration](/multisig-for-protocols/setup-and-configuration) - [Multisig Registration & Documentation](/multisig-for-protocols/registration-and-documentation) diff --git a/docs/pages/multisig-for-protocols/joining-a-multisig.mdx b/docs/pages/multisig-for-protocols/joining-a-multisig.mdx index 65788d99..fab38a9a 100644 --- a/docs/pages/multisig-for-protocols/joining-a-multisig.mdx +++ b/docs/pages/multisig-for-protocols/joining-a-multisig.mdx @@ -22,7 +22,18 @@ import { TagList, AttributionList, TagProvider, TagFilter, ContributeFooter } fr -It is recommended to always create a fresh address on a hardware wallet for each new multisig. +## Use a Dedicated Key for Each Multisig + +Always create a fresh address on a hardware wallet for each new multisig you join. Use a different address index on +your hardware wallet (same derivation path, just switch between addresses) and label each clearly. + +This matters for two reasons: + +- **Signing clarity**: With a dedicated key, your wallet interface only shows transactions from one multisig. This + eliminates confusion about which multisig a signing request belongs to and reduces the risk of signing the wrong + transaction. +- **Key isolation**: If your key for one multisig is compromised, it cannot be used to attack any other multisig you + participate in. Each multisig has an independent security boundary. ## Verifying address ownership diff --git a/docs/pages/multisig-for-protocols/key-takeaways.mdx b/docs/pages/multisig-for-protocols/key-takeaways.mdx new file mode 100644 index 00000000..bddb7d02 --- /dev/null +++ b/docs/pages/multisig-for-protocols/key-takeaways.mdx @@ -0,0 +1,115 @@ +--- +title: "Multisig Key Takeaways | SEAL" +description: "The most important multisig security principles on one page. Timelocks, multisig separation, address discipline, monitoring, and calldata verification." +tags: + - Engineer/Developer + - Security Specialist + - Operations & Strategy + - Multisig Security +contributors: + - role: wrote + users: [isaac] + - role: reviewed + users: [] +--- + +import { TagList, AttributionList, TagProvider, TagFilter, ContributeFooter } from '../../../components' + + + + +# Key Takeaways + + + + +If you read one page from the Multisig Security Framework, make it this one. These are the principles that matter most. + +## 1. Use Timelocks on All Admin Changes + +Any multisig controlling protocol parameters or upgrades should route through a +[timelock contract](/multisig-for-protocols/use-case-specific-requirements#timelock-configuration). Without a timelock, +once threshold signatures are collected, changes take effect immediately with no chance to detect or stop a malicious +proposal. Use +[tiered durations](/multisig-for-protocols/use-case-specific-requirements#tiered-timelock-durations): longer delays for +major changes (upgrades, token changes), shorter delays for routine parameter tuning. + +## 2. Separate Multisigs by Function + +Do not put all admin privileges in one multisig. If that single multisig is compromised, everything is lost. Use +[separate multisigs](/multisig-for-protocols/use-case-specific-requirements#separating-multisigs-by-function) for +different functional areas (protocol upgrades, operational parameters, emergency pause, treasury) with tailored +thresholds and signer sets for each. + +## 3. Use Dedicated Keys Per Multisig + +Each signer should use a +[different address](/wallet-security/secure-multisig-best-practices#dedicated-keys-per-multisig) for each multisig. +This makes it easy to distinguish which multisig a transaction belongs to in your wallet, and prevents a compromised key +from being usable across multiple multisigs. Same derivation path on your hardware wallet, just different address +indexes. + +## 4. Maintain an Access Control Inventory + +Keep a living document of every privileged role in your protocol: what it can do, which multisig holds it, what +constraints exist, and what the blast radius is if compromised. You cannot design proper multisig separation or classify +risk without this foundation. See +[Access Control Inventory](/multisig-for-protocols/planning-and-classification#maintain-an-access-control-inventory). + +## 5. Constrain Emergency Powers + +If emergency bypass mechanisms exist (e.g., bypassing a timelock), they should be limited to the minimum necessary +action like pausing. An emergency path should never be able to upgrade contracts or move funds. This way, even +maliciously obtained emergency signatures cause minimal damage. See +[Design Principles](/wallet-security/secure-multisig-best-practices#constrain-emergency-powers). + +## 6. Monitor Timelock Queues Actively + +A timelock without monitoring provides no protection. Implement +[automated alerting](/multisig-for-protocols/use-case-specific-requirements#timelock-monitoring) that watches for queued +transactions and immediately notifies the team with decoded transaction details. At least one monitoring channel should +be operated by an external party so internal compromise cannot suppress alerts. + +## 7. Never Copy Addresses from Explorer History + +Always use a verified +[address book](/wallet-security/secure-multisig-best-practices#address-book-discipline). Never copy addresses from block +explorer transaction history, Etherscan, or chat messages. For first-time recipients, perform a bidirectional test +transaction. For high-value transfers, verify addresses character-by-character on a video call. + +## 8. Watch for Permissionless Safe Additions + +Anyone can create a Safe and add you as an owner without your consent, making it appear in your Safe app. Attackers +create Safes with addresses matching the first 4 and last 4 characters of your real Safes. Always verify the full +address and navigate from bookmarks, not the dashboard. See +[Address Poisoning](/wallet-security/secure-multisig-best-practices#address-poisoning-and-permissionless-safe-additions). + +## 9. Verify Calldata, Not Just Hashes + +Hash verification confirms you are signing the intended transaction, but it does not tell you what the transaction does. +Always [decode the calldata](/wallet-security/signing-and-verification/secure-multisig-safe-verification#5-calldata-review) +and verify the function, target, and parameters match what was described. Watch for red flags like unexpected +`DELEGATECALL`, `approve` calls, or hidden batch operations. + +## 10. Use Delegated Proposers and Non-Signer Execution + +Set up a [delegated proposer](/multisig-for-protocols/setup-and-configuration#delegated-proposer) for Safe multisigs. +Hash verification tools rely on the Safe API, which only has data after a transaction is proposed. Without a delegated +proposer, the first signer faces additional challenges to verify what they are signing. For a related reason, avoid "sign and execute" for the final signature, as verification tools do not provide the +expected hashes for this combined action. Instead, have all signers sign only, then have a non-signer execute the +fully-signed transaction. + +## 11. Hardware Wallets, Backup Infrastructure, and Drills + +All signers must use hardware wallets. Maintain +[backup signing infrastructure](/multisig-for-protocols/backup-signing-and-infrastructure) (Eternal Safe, Squads Public +Client) in case primary UIs go down. Run regular emergency drills to verify that signers can respond under pressure and +that communication channels work. See the +[Implementation Checklist](/multisig-for-protocols/implementation-checklist). + +--- + +For the full framework, see the [Multisig Security Framework Overview](/multisig-for-protocols/overview). + + + diff --git a/docs/pages/multisig-for-protocols/overview.mdx b/docs/pages/multisig-for-protocols/overview.mdx index 56802f2e..9039cd99 100644 --- a/docs/pages/multisig-for-protocols/overview.mdx +++ b/docs/pages/multisig-for-protocols/overview.mdx @@ -24,6 +24,9 @@ import { TagList, AttributionList, TagProvider, TagFilter, ContributeFooter } fr ## How to use this guide +**Short on time?** Start with [Key Takeaways](/multisig-for-protocols/key-takeaways) for the most important points +on one page. + **Quick start**: New to multisigs? Start with the Foundation for the essentials, then jump to your role: - Setting up a new multisig? → Multisig Administration: [Setup & @@ -39,6 +42,8 @@ import { TagList, AttributionList, TagProvider, TagFilter, ContributeFooter } fr ## Core principles - **Security first**: Every multisig must meet [minimum security standards](/wallet-security/secure-multisig-best-practices) +- **Built-in slowness**: Timelocks and review windows are intentional security mechanisms, not obstacles to work around +- **Constrained emergency powers**: Emergency bypass mechanisms should do the minimum necessary and nothing more - **Operational readiness**: Procedures that work under pressure - **Clear accountability**: Everyone knows their role and responsibilities - **Emergency preparedness**: Plans for when things go wrong diff --git a/docs/pages/multisig-for-protocols/planning-and-classification.mdx b/docs/pages/multisig-for-protocols/planning-and-classification.mdx index 8f506f37..766302ad 100644 --- a/docs/pages/multisig-for-protocols/planning-and-classification.mdx +++ b/docs/pages/multisig-for-protocols/planning-and-classification.mdx @@ -43,6 +43,27 @@ Document the multisig's intended use: - **Decision timeline** - How quickly must it respond? - **Integration points** - What systems will it interact with? +### Maintain an Access Control Inventory + +Before classifying multisigs, protocols should first build a comprehensive inventory of all privileged roles in their +system. You cannot classify risk or design multisig separation if you do not know what powers exist and where they live. + +For each privileged role, document: + +- **Role name**: The on-chain role or permission (e.g., `UPGRADER_ROLE`, `owner`, `pauser`, `fee-setter`) +- **Held by**: Which address or multisig currently holds this role +- **Contract**: Which contract(s) this role controls +- **Capabilities**: What this role can do (specific functions and their effects) +- **Constraints**: What limits exist on this role (timelocks, parameter bounds, governance controls) +- **Blast radius**: The maximum potential impact if this role is compromised + +This inventory is the foundation for all multisig planning — it directly informs how many multisigs you need, how to +separate responsibilities, and what threshold and timelock configurations to use. Maintain it as a living document, +updated whenever new contracts are deployed or roles change. + +See the [Registration Template](/multisig-for-protocols/registration-and-documentation#registration-template) for how +to document this per multisig. + ### Assess Constraints and Recovery Consider limiting factors that affect risk: diff --git a/docs/pages/multisig-for-protocols/registration-and-documentation.mdx b/docs/pages/multisig-for-protocols/registration-and-documentation.mdx index ac323e4d..68c25996 100644 --- a/docs/pages/multisig-for-protocols/registration-and-documentation.mdx +++ b/docs/pages/multisig-for-protocols/registration-and-documentation.mdx @@ -47,6 +47,17 @@ Signers: Controlled contracts: [List contract addresses and purposes] On-chain roles: [Describe roles like ownable, Access Control roles (PAUSER_ROLE)] +Access Control Inventory: +- Role: [Role name, e.g., UPGRADER_ROLE] + Held by: [This multisig address] + Contract: [Contract address and name] + Capabilities: [What this role can do] + Constraints: [Timelock duration, parameter bounds, etc.] + Blast radius: [Maximum potential impact if compromised] + +Timelock configuration: [Timelock contract address, delay duration, who can cancel] +Related multisigs: [Other multisigs that interact with the same contracts or share signers] + Impact assessment: - Financial exposure: $[amount] ([reasoning]) - Protocol impact: [description] diff --git a/docs/pages/multisig-for-protocols/setup-and-configuration.mdx b/docs/pages/multisig-for-protocols/setup-and-configuration.mdx index f51016d3..cc993004 100644 --- a/docs/pages/multisig-for-protocols/setup-and-configuration.mdx +++ b/docs/pages/multisig-for-protocols/setup-and-configuration.mdx @@ -53,12 +53,17 @@ For emergency situations when the primary UI is unavailable, see ## Delegated Proposer -It is recommended, but not required to authorize a separate transaction proposer for a Safe. This address can prepare -transactions for signers to sign but is not an authorized signer on the Safe. Therefore **there is no risk of malicious -signatures which can affect the Safe assets**. This wallet can hold no funds and simply act as a proposer. The primary -reason to have a delegated proposer is that the hash verification utilities depend on the Safe API (unless details are -entered manually). Until a transaction is **proposed** it does not show up in the API so the hash verification tools -cannot detect it. +It is recommended to authorize a separate transaction proposer for a Safe. This address can prepare transactions for +signers to sign but is not an authorized signer on the Safe. This wallet can hold no funds and simply acts as a +proposer. + +Hash verification tools rely on the Safe API, which only has transaction data after the transaction is proposed. +Without a delegated proposer, the first signer faces additional challenges to verify what they are signing. A +delegated proposer submits the transaction to the API before any signer approves, so every signer can verify. + +For a related reason, the final signer should avoid "sign and execute." Verification tools do not provide the expected +hashes for this combined action. Instead, have all signers sign only, then have a non-signer execute the fully-signed +transaction. ![Delegated proposer configuration interface](https://frameworks-static.s3.us-east-2.amazonaws.com/images/multisig-for-protocols/delegated-proposer-configuration-interface.png) @@ -160,6 +165,16 @@ Implement monitoring and alerting systems to be immediately notified of any on-c including proposed transactions, new signatures, and owner changes (e.g., using tools like [Safe Watcher](https://github.com/Gearbox-protocol/safe-watcher)). +Monitoring should also cover activity on individual signer addresses to detect unauthorized use of signer keys outside +the multisig context. + +### Timelock Transaction Monitoring + +For any multisig that uses a timelock, configure automated monitoring for all timelock events (queue, execute, cancel). +Alerts should fire immediately when a new transaction is queued, providing decoded calldata and a countdown to the +execution window. See +[Timelock Monitoring](/multisig-for-protocols/use-case-specific-requirements#timelock-monitoring) for full requirements. + ### Immutable Monitoring Channels Monitoring channels (e.g. email, Slack or Telegram chats) must be immutable (or trigger alerts when their configuration diff --git a/docs/pages/multisig-for-protocols/use-case-specific-requirements.mdx b/docs/pages/multisig-for-protocols/use-case-specific-requirements.mdx index 2b728c56..4027a134 100644 --- a/docs/pages/multisig-for-protocols/use-case-specific-requirements.mdx +++ b/docs/pages/multisig-for-protocols/use-case-specific-requirements.mdx @@ -22,6 +22,40 @@ import { TagList, AttributionList, TagProvider, TagFilter, ContributeFooter } fr +## Separating Multisigs by Function + +Protocols should not consolidate all admin privileges into a single multisig. If one multisig controls everything +(treasury, protocol upgrades, operational parameters, emergency pause), then compromising that multisig means total +protocol compromise. + +### Why Separation Matters + +- **Blast radius**: Separate multisigs limit the damage from any single compromise to one functional area +- **Right-sized security**: Different functions have different risk profiles. Routine parameter changes need different + thresholds and response times than contract upgrades. Separate multisigs allow tailored security per function. +- **Signer expertise**: Protocol upgrade signers need deep technical expertise. Treasury signers need financial + operations expertise. Separation puts the right people on each function. + +### Common Separation Patterns + +| Function | Typical Threshold | Timelock | Notes | +| -------- | ----------------- | -------- | ----- | +| Protocol upgrades | High (e.g., 7/9+) | Long (7-14+ days) | Highest security, infrequent use | +| Operational parameters | Moderate (e.g., 3/5) | Medium (48-72 hours) | Routine tuning within bounds | +| Emergency pause | Lower (e.g., 2/4) | None | Constrained to pause-only actions | +| Treasury | High (e.g., 4/7) | Varies | Separate signer set from protocol admin | +| Specialized subsystem | Moderate | Medium | Domain-expert signers (e.g., oracle config, bridge params) | + +### Implementation Guidance + +- Document which multisig controls which contracts and roles in the + [Registration Template](/multisig-for-protocols/registration-and-documentation#registration-template) +- Use separate on-chain roles (e.g., OpenZeppelin AccessControl) mapped to separate multisigs +- No single multisig should have both "pause" and "upgrade" capabilities unless the upgrade path is gated by a timelock +- Use [dedicated signing keys](/wallet-security/secure-multisig-best-practices#dedicated-keys-per-multisig) per multisig + so signers can easily distinguish which multisig a transaction belongs to, and so attackers cannot reuse compromised + keys across multisigs + ## Treasury Multisigs ### Key requirements: @@ -91,11 +125,42 @@ to provide adequate time to respond in the event of an anomaly ## Timelock Configuration -For sensitive protocol operations like configuration changes or upgrades it is recommended to use a timelock contract -(eg. [OpenZeppelin Timelock Controller](https://docs.openzeppelin.com/contracts/5.x/api/governance#TimelockController)) -to stage transactions on-chain for final verification before execution. It is not necessary to have a long delay. Some -timelock contracts are even configured with 0 delay. The key is to have the full transaction payload fully on chain -after signature with a final opportunity to review it and cancel it. +Timelocks are essential for any multisig controlling protocol parameters, upgrades, or user-facing configuration. A +multisig without a timelock means that once threshold signatures are collected, changes take effect immediately with +no opportunity for detection or intervention. + +Use a timelock contract (e.g., +[OpenZeppelin Timelock Controller](https://docs.openzeppelin.com/contracts/5.x/api/governance#TimelockController)) +to stage transactions on-chain for final verification before execution. + +### Why Timelocks Are Critical + +Without a timelock, the only defense is that the threshold number of signers are all honest and careful at all times. +This is a fragile assumption. Timelocks create a public review window: once a transaction is queued, anyone monitoring +the chain can see what is about to happen. This enables detection of malicious or incorrect proposals before they +execute. + +Timelocks are only effective if someone is actively watching. See +[Timelock Monitoring](#timelock-monitoring) below. + +### Tiered Timelock Durations + +Not all changes carry the same risk. Protocols should use different timelock durations based on the severity of the +change: + +- **Long (7-14+ days)**: Major changes that affect user funds or fundamental protocol behavior such as contract + upgrades, token contract changes, or reward distribution changes. Users need time to react (e.g., withdraw funds + or unbond stake). +- **Medium (48-72 hours)**: Significant operational changes such as fee parameter updates, validator set + configuration, or oracle changes. The team and external monitors need time to review. +- **Short (hours to 1 day)**: Routine parameter adjustments within predefined bounds. Still provides a verification + window without impeding normal operations. +- **No timelock (direct execution)**: Reserved only for emergency actions that are highly constrained in scope + (e.g., pause-only capability). See + [Design Principles](/wallet-security/secure-multisig-best-practices#constrain-emergency-powers). + +The appropriate duration depends on how much time users need to react, the potential impact if the change is malicious, +and the operational cadence of the change. ### Configuration @@ -115,7 +180,9 @@ go through the timelock stage. ### Recommended Time-Lock Delays -Time-locks should delay transactions a minimum of 3 days. +As a default, time-locks should delay transactions a minimum of 3 days. Use the tiered approach above to adjust based +on the type of change. Even a short delay (e.g., 1 hour) with active monitoring is significantly better than no delay +at all. ### Simulation Consideration @@ -125,5 +192,30 @@ shown in [Simulation testing](/wallet-security/signing-and-verification/secure-m ![Timelock configuration diagram](https://frameworks-static.s3.us-east-2.amazonaws.com/images/multisig-for-protocols/timelock-configuration-diagram.png) +## Timelock Monitoring + +A timelock without active monitoring provides no protection. If no one watches for queued transactions, a malicious +proposal will simply execute after the delay period. The monitoring window IS the security mechanism. + +### Requirements + +- **Automated alerting**: Implement monitoring that watches for all timelock events (`CallScheduled`, `CallExecuted`, + `Cancelled`, or equivalent) and immediately alerts the multisig signer team and external monitors +- **Decoded transaction details**: Alerts should include the full decoded transaction details (target contract, + function, parameters), not just a notification that something was queued. This allows reviewers to quickly assess + whether the transaction is expected and correct. +- **Response procedures**: Document what to do when a timelock alert fires: who reviews it, how it is verified as + legitimate, and how to cancel if it is malicious or incorrect +- **External monitoring**: At least one monitoring channel should be operated by a party external to the core team, + so that an internal compromise cannot suppress alerts. See + [External Transaction Monitoring](#external-transaction-monitoring) for treasury-specific requirements. +- **Redundant channels**: Use multiple independent alert channels (e.g., email, Slack, Telegram) so that a single + channel failure does not cause a missed alert + +### Community Visibility + +Consider making timelock queues publicly visible through a dashboard or notification feed. This allows the broader +community to observe pending changes, which adds an additional layer of scrutiny beyond the core team. + diff --git a/docs/pages/wallet-security/secure-multisig-best-practices.mdx b/docs/pages/wallet-security/secure-multisig-best-practices.mdx index 9e011a2e..b77ad5df 100644 --- a/docs/pages/wallet-security/secure-multisig-best-practices.mdx +++ b/docs/pages/wallet-security/secure-multisig-best-practices.mdx @@ -36,6 +36,32 @@ managing protocol treasuries, smart contract ownership, or significant personal/ The primary objective is to eliminate single points of failure and establish robust, distributed control over high-value assets and critical smart contract functions. +## Design Principles + +### Build in Slowness by Design + +Actions that affect user funds or protocol security should be made deliberately slow through +[timelocks](/multisig-for-protocols/use-case-specific-requirements#timelock-configuration) and review windows. +Speed is a risk. Forced urgency is one of the primary tools attackers use in social engineering and key compromise +scenarios. Legitimate operations can accommodate delays, and the slower the path, the more opportunities exist for +detection and intervention. + +### Constrain Emergency Powers + +If emergency bypass mechanisms exist (such as bypassing a timelock), they should be highly constrained to the minimum +necessary action. For example, an emergency path should only be able to pause the protocol, not upgrade contracts or +move funds. This way, even if emergency signatures are obtained maliciously, the damage is limited to a temporary pause +rather than a full protocol takeover. The more powerful an action, the more restrictions and delays it should require. + +### Separate Responsibilities Across Multisigs + +Protocols should not consolidate all admin privileges into a single multisig. Different functional areas (protocol +upgrades, operational parameter changes, emergency response, treasury management) should be controlled by separate +multisigs with potentially different signer sets and thresholds. This limits the blast radius of any single compromise +and allows security measures to be tailored to each function's risk profile. See +[Separating Multisigs by Function](/multisig-for-protocols/use-case-specific-requirements#separating-multisigs-by-function) +for detailed guidance. + ## Core Concept: M-of-N Scheme A multisignature (multisig) wallet is a smart contract that requires a predefined minimum number of approvals `M` from a @@ -57,8 +83,6 @@ authorize the movement of funds or execute a privileged action. for more information on threshold selection. - All signers must use hardware wallets - Multisigs managing assets on behalf of a DAO should set unlimited allowance with primary DAO agent -- Signers on multisigs with critical protocol configuration or security roles are discouraged from using their -addresses for other purposes. They should create a brand new wallet for that purpose instead. - All signing wallets should be monitored for any activity that is not directly related to multi-sig operations. - No multisigs should use modules/guards except those mentioned in [Setup & Configuration → Modules & Guards](/multisig-for-protocols/setup-and-configuration#modules--guards) @@ -71,6 +95,20 @@ replace the multisig. Avoid `N-of-N` schemes, as the loss of a single key would result in a permanent loss of access to all funds. +#### Dedicated Keys Per Multisig + +Signers should use a dedicated address for each multisig they participate in: + +- **Wallet clarity**: When a signer uses the same key across multiple multisigs, signing requests become ambiguous. + A dedicated key per multisig makes it immediately obvious which multisig a transaction belongs to, reducing the + chance of signing the wrong transaction. +- **Blast radius containment**: If an attacker compromises a signer's key that is shared across multiple multisigs, + the attacker gains a valid signature on every multisig that key belongs to. With dedicated keys, compromising one + key only affects one multisig. + +In practice, use a different address index on your hardware wallet for each multisig — same derivation path, just +switch between addresses and label each clearly in your wallet interface. + #### Strategic Signer Distribution The security of a multisig depends entirely on the operational security (OpSec) of its individual signer keys. Storing @@ -186,6 +224,40 @@ related to the multisig, including proposed transactions, new signatures, and ow Require a "how to check" guide and communicate status after signing (e.g., "checked, signed, X more required"). Last signer executes when applicable. +### Address Book Discipline + +The single most common cause of misdirected funds is using an incorrect address. Protocols must enforce strict address +hygiene: + +- **Never** copy addresses from block explorer transaction history, Etherscan address pages, or chat/email messages. + These are all vectors for address poisoning attacks where attackers create transactions from addresses that resemble + legitimate ones. +- **Always** copy addresses from a verified, maintained address book or directly from the multisig/custody platform + interface. +- **First-time recipients**: Before sending any meaningful value to a new address, perform a bidirectional test + transaction. Send a small amount, have the recipient confirm receipt and send a small amount back. This proves + both parties control the addresses they claim. +- **High-value transfers**: For transfers above a protocol-defined threshold, verify the recipient address + character-by-character on a video call with all approvers. +- **Address changes**: If a counterparty requests a change to a previously verified address, treat it as a full + re-verification event. Do not simply update the address book based on a message. + +### Address Poisoning and Permissionless Safe Additions + +Anyone can create a Safe and add your address as an owner without your consent. This Safe will appear in your Safe app +dashboard alongside your legitimate Safes. Attackers exploit this by creating Safes with addresses that share the same +first 4 and last 4 hex characters as your real Safes, making them visually similar in truncated address displays. + +If you are not careful about which Safe you select in the UI, you may interact with or send funds to the attacker's +Safe. + +**Mitigations**: + +- Always verify the **full** Safe address before interacting, not just the first and last few characters +- Bookmark your legitimate Safe addresses and navigate to them directly rather than selecting from a dashboard list +- If a new Safe appears in your dashboard that you did not create or expect, **do not interact with it** +- Use your verified address book to confirm any Safe address before transacting + ## Contract-Level Security - **Invariant Enforcement:** Design contracts to enforce invariants and expected state changes such as token balance diff --git a/docs/pages/wallet-security/signing-and-verification/secure-multisig-safe-verification.mdx b/docs/pages/wallet-security/signing-and-verification/secure-multisig-safe-verification.mdx index 7cb01d71..6721d06e 100644 --- a/docs/pages/wallet-security/signing-and-verification/secure-multisig-safe-verification.mdx +++ b/docs/pages/wallet-security/signing-and-verification/secure-multisig-safe-verification.mdx @@ -46,6 +46,15 @@ flow. The goal is to ensure that what you see in the UI matches what your hardwa execute, communicate with other signers - **Re-verify before execution**: If executing an already signed transaction, check it as if you were signing it +## Verify You Are on the Correct Safe + +Before interacting with any Safe, verify you are on the correct Safe address. Anyone can create a Safe and add you +as an owner without your consent, and attackers create Safes with addresses designed to look similar to your +legitimate Safes (matching first and last 4 characters). Always navigate to your Safe from a bookmarked or verified +address, not from the Safe app dashboard list. See +[Address Poisoning](/wallet-security/secure-multisig-best-practices#address-poisoning-and-permissionless-safe-additions) +for details. + ## Key Definitions (EVM) - Domain Hash (EIP-712 domain separator) @@ -122,12 +131,44 @@ Important: Both tools require checksummed addresses: ## 5) Calldata Review -- Decode calldata (e.g., SwissKnife) -- Verify functions, recipients, amounts; watch for risky operations +Hash verification confirms you are signing the right transaction (the one that was proposed), but the hash alone does +not tell you what the transaction actually does. You need to decode the calldata to understand the on-chain action. +Never sign a transaction you do not understand. + +### How Calldata Works + +EVM calldata consists of: + +- **Function selector** (first 4 bytes): Identifies which function is being called. For example, `0xa9059cbb` is the + selector for `transfer(address,uint256)`. +- **ABI-encoded parameters** (remaining bytes): The function arguments encoded according to the Solidity ABI + specification. + +For batch transactions using MultiSend, the calldata contains multiple packed transactions. Each must be individually +decoded and reviewed. + +### Decoding Steps + +1. Copy the calldata from the Safe UI or from the hash verification tool +2. Paste into a decoder (e.g., SwissKnife Calldata Decoder, Foundry `cast decode-calldata`) +3. Verify the function name, target address, and parameters match the expected values +4. For protocol-specific functions, consider building internal decoding tooling tailored to your contracts for + human-readable output + +### Common Red Flags + +- **`DELEGATECALL` (operation type 1)**: Gives the target contract full control over the Safe's storage. Should only + appear when the target is a known, audited module. +- **Unexpected `approve` or `setApprovalForAll` calls**: Could grant unlimited token spending to an attacker's address. +- **`MultiSend` when a single action was expected**: Extra calls could be hidden in a batch. +- **Unfamiliar function selectors**: If you cannot identify the function being called, do not sign until you verify it. +- **Parameters that do not match the briefing**: Wrong recipient, wrong amount, wrong contract address. +- **Mismatched target contract**: The function call is going to a different contract than described. -### Tool diversity recommendation +### Tool Diversity Recommendation -Signers should not all use identical tools. Cross-verify results between multiple tools (CLI and web) for critical operations. +Signers should not all use identical tools. Cross-verify results between multiple tools (CLI and web) for critical +operations. ## Special Cases: Nested Safes diff --git a/docs/pages/wallet-security/signing-and-verification/secure-multisig-squads-verification.mdx b/docs/pages/wallet-security/signing-and-verification/secure-multisig-squads-verification.mdx index f0d96130..d28f1514 100644 --- a/docs/pages/wallet-security/signing-and-verification/secure-multisig-squads-verification.mdx +++ b/docs/pages/wallet-security/signing-and-verification/secure-multisig-squads-verification.mdx @@ -24,6 +24,22 @@ Limited tooling is available for Solana verification compared to EVM. Exercise e +## Solana vs. EVM: Key Differences for Multisig Security + +Solana multisigs operate differently from EVM-based Safes in several important ways: + +- **Transaction model**: Solana transactions contain a list of instructions rather than a single ABI-encoded calldata + payload. Verification requires inspecting each instruction individually. +- **Limited tooling**: Solana verification tooling is significantly less mature than EVM. There are no widely adopted + equivalents to Safe CLI hash verification utilities or calldata decoders. Signers must rely more heavily on manual + inspection and cross-verification with team members. +- **UI-dependent verification**: Instead of hash-based verification against the hardware wallet display, Squads + verification relies on inspecting transaction data through the Solana explorer and simulation tools. This makes the + verification process more dependent on the UI and explorer being accurate. +- **Program-based architecture**: Solana uses programs with instruction data rather than function selectors and + ABI-encoded calldata. Understanding the raw instruction bytes requires knowledge of the specific program's + instruction format. + ## Workflow 1) Initial Proposal (SOL transfer, token transfer, signer/threshold change) @@ -118,5 +134,6 @@ Simulation does NOT seem to work for configuration changes, but we have another - Execute after collecting all signatures - Once all signatures are collected, execute the transaction. + diff --git a/utils/fetched-tags.json b/utils/fetched-tags.json index 94e7693b..d52c1de2 100644 --- a/utils/fetched-tags.json +++ b/utils/fetched-tags.json @@ -799,6 +799,12 @@ "Security Specialist", "Multisig Security" ], + "/multisig-for-protocols/key-takeaways": [ + "Engineer/Developer", + "Security Specialist", + "Operations & Strategy", + "Multisig Security" + ], "/multisig-for-protocols/offboarding": [ "Engineer/Developer", "Security Specialist", @@ -1269,45 +1275,45 @@ ] }, "sectionMappings": { - "Community Management": "community-management", + "AI Security": "ai-security", "Awareness": "awareness", - "Operational Security": "opsec", - "OpSec Core Concepts": "opsec", - "While Traveling": "opsec", - "Wallet Security": "wallet-security", - "Signing & Verification": "wallet-security", - "Multisig for Protocols": "multisig-for-protocols", - "Multisig Administration": "multisig-for-protocols", - "Operational Runbooks": "multisig-for-protocols", - "For Signers": "multisig-for-protocols", + "Community Management": "community-management", + "DevSecOps": "devsecops", + "Isolation & Sandboxing": "devsecops", + "DPRK IT Workers": "dprk-it-workers", + "Encryption": "encryption", + "ENS": "ens", "External Security Reviews": "external-security-reviews", "Smart Contract Audits": "external-security-reviews", - "Vulnerability Disclosure": "vulnerability-disclosure", - "Infrastructure": "infrastructure", - "Domain & DNS Security": "infrastructure", - "Monitoring": "monitoring", "Front-End/Web Application": "front-end-web-app", + "Governance": "governance", + "Identity and Access Management IAM": "iam", "Incident Management": "incident-management", "Playbooks": "incident-management", "Incident Response Template": "incident-management", "Templates": "incident-management", "Runbooks": "incident-management", - "Threat Modeling": "threat-modeling", - "DPRK IT Workers": "dprk-it-workers", - "Governance": "governance", - "DevSecOps": "devsecops", - "Isolation & Sandboxing": "devsecops", + "Infrastructure": "infrastructure", + "Domain & DNS Security": "infrastructure", + "Monitoring": "monitoring", + "Multisig for Protocols": "multisig-for-protocols", + "Multisig Administration": "multisig-for-protocols", + "Operational Runbooks": "multisig-for-protocols", + "For Signers": "multisig-for-protocols", + "Operational Security": "opsec", + "OpSec Core Concepts": "opsec", + "While Traveling": "opsec", "Privacy": "privacy", - "Supply Chain": "supply-chain", - "Security Automation": "security-automation", - "Identity and Access Management IAM": "iam", + "Safe Harbor": "safe-harbor", "Secure Software Development": "secure-software-development", + "Security Automation": "security-automation", "Security Testing": "security-testing", - "AI Security": "ai-security", - "ENS": "ens", - "Safe Harbor": "safe-harbor", - "Encryption": "encryption", + "Supply Chain": "supply-chain", + "Threat Modeling": "threat-modeling", "Treasury Operations": "treasury-operations", + "Vulnerability Disclosure": "vulnerability-disclosure", + "Wallet Security": "wallet-security", + "Signing & Verification": "wallet-security", "Guides": "guides", "Account Management": "guides", "Endpoint Security": "guides", diff --git a/vocs.config.tsx b/vocs.config.tsx index bd89b9ef..600a2807 100644 --- a/vocs.config.tsx +++ b/vocs.config.tsx @@ -305,6 +305,7 @@ const config = { collapsed: true, items: [ { text: 'Overview', link: '/multisig-for-protocols/overview' }, + { text: 'Key Takeaways', link: '/multisig-for-protocols/key-takeaways' }, { text: 'Multisig Administration',