HomeLearning pathMulti-sig walletsSmart contract auditingPhishing awarenessVerify team member
Start learning
Interactive course5 modules

Web3 security learning path

Master the fundamentals of blockchain security through hands-on modules, real-world examples, and knowledge checks. Complete each module to track your progress.

Your learning progress
0 of 5 modules completed
1. Wallet security
2. Transactions
3. Smart contracts
4. Social engineering
5. Org security
1

Wallet security fundamentals

Beginner15 min

Seed phrases: the master key to your assets

A seed phrase (also called a mnemonic phrase or recovery phrase) is a human-readable representation of your wallet's master private key. Defined by BIP-39, it consists of 12 or 24 words drawn from a standardized list of 2,048 English words. From this single phrase, all of your private keys, public keys, and addresses are mathematically derived.

The seed phrase is the single most critical piece of security in your entire crypto setup. Anyone who obtains your seed phrase has complete, irreversible control over every account derived from it -- across every chain, every token, every NFT.

Never share your seed phrase

No legitimate service, wallet, or support team will ever ask for your seed phrase. If someone asks for it, it is a scam -- 100% of the time, with zero exceptions. Do not type it into any website, do not store it in a cloud document, and do not photograph it with your phone.

Secure seed phrase storage

Bad practices
  • Storing in a notes app or text file
  • Taking a screenshot or photo
  • Saving in cloud storage (iCloud, Google Drive)
  • Emailing it to yourself
  • Storing the entire phrase in one location
Best practices
  • Write on paper, store in a fireproof safe
  • Engrave on a steel plate (Cryptosteel, Billfodl)
  • Split using Shamir's Secret Sharing
  • Store backup copies in separate geographic locations
  • Use a BIP-39 passphrase (25th word) as added protection

Hardware wallets: your offline fortress

A hardware wallet is a specialized physical device that stores your private keys in a secure element -- an isolated chip that never exposes the keys to your computer or the internet. When you sign a transaction, the data is sent to the device, signed inside the secure element, and only the signed result is sent back. The private key never leaves the device.

Ledger devices

Uses a certified Secure Element (SE) chip (ST33/ST31). Supports Ledger Live and third-party wallets. Models: Nano S Plus, Nano X, Stax.

Trezor devices

Open-source firmware and hardware. Uses a general-purpose MCU (not SE). Models: Trezor Model One, Model T, Safe 3 (adds SE chip).

Supply chain attacks

Always purchase hardware wallets directly from the manufacturer. Tampered devices sold through third-party resellers have been used to steal funds. When your device arrives, verify the tamper-evident packaging is intact and run the manufacturer's genuineness check.

HD wallets and derivation paths

Hierarchical Deterministic (HD) wallets, defined by BIP-32 and BIP-44, generate an entire tree of key pairs from a single seed. Each "branch" follows a derivation path that looks like this:

// BIP-44 Derivation Path Structure m / purpose' / coin_type' / account' / change / address_index // Examples: m/44'/60'/0'/0/0 // First Ethereum address m/44'/60'/0'/0/1 // Second Ethereum address m/44'/0'/0'/0/0 // First Bitcoin address m/44'/501'/0'/0' // First Solana address

This means a single seed phrase can control addresses across every blockchain. It also means losing that seed phrase compromises everything.

Account types: EOA vs. smart contract wallets

  • Externally Owned Account (EOA): Controlled by a single private key. This is what MetaMask, Ledger, and Trezor create. Simple but fragile -- lose the key, lose everything. No recovery options, no spending limits, no access control.
  • Smart Contract Wallet (e.g., Safe, Argent): A wallet implemented as a smart contract on-chain. Supports multi-signature approval, spending limits, social recovery, account freezing, and programmable access control. The industry is moving toward these as the standard for organizational use.
Account abstraction (ERC-4337)

ERC-4337 brings smart contract wallet functionality to Ethereum without requiring protocol changes. It enables gas sponsorship (so users do not need ETH for gas), batched transactions, session keys, and custom validation logic. This is the future direction for all wallet security.

What is the primary security advantage of a hardware wallet over a software wallet like MetaMask?
It supports more blockchains and tokens
It has a more user-friendly interface
Private keys are stored in an offline secure element and never exposed to the internet
It automatically backs up your seed phrase to the cloud
Why is a single compromised seed phrase so dangerous in the context of HD wallets?
It only affects the first address generated from the seed
All accounts across all blockchains derived from that seed are compromised
Only the Ethereum accounts are affected, not Bitcoin
The seed phrase can only be used once, so it is not that dangerous
2

Understanding transactions

Intermediate20 min

How transaction signing works

Every Ethereum transaction must be cryptographically signed with the sender's private key before it can be broadcast to the network. The signing process uses the Elliptic Curve Digital Signature Algorithm (ECDSA) with the secp256k1 curve. Here is what happens step by step:

  1. Transaction construction: Your wallet assembles the transaction data -- recipient address, value, gas limit, gas price, nonce, and calldata (for contract interactions).
  2. RLP encoding: The transaction fields are serialized using Recursive Length Prefix (RLP) encoding.
  3. Keccak-256 hashing: The encoded transaction is hashed to produce a 32-byte digest.
  4. ECDSA signing: Your private key signs the hash, producing the signature components (v, r, s).
  5. Broadcast: The signed transaction is submitted to the network. Validators verify the signature matches the sender's address before including it in a block.
The nonce is critical

The nonce is a sequential counter that prevents replay attacks. Each transaction from an address must use the next nonce in sequence. If you submit a transaction with nonce 5, nonce 4 must have already been mined. This is also why "stuck" transactions happen -- a pending transaction with a lower nonce blocks all subsequent ones.

Token approvals: the silent danger

Before a smart contract (like a DEX or lending protocol) can move your ERC-20 tokens, you must first call the approve() function on the token contract. This grants the spender address permission to transfer up to the approved amount of your tokens.

// ERC-20 approve function function approve(address spender, uint256 amount) external returns (bool); // What happens when you "approve USDC on Uniswap": // You call: USDC.approve(UniswapRouter, 115792...very large number) // This gives Uniswap permission to transfer up to that amount of your USDC

The problem: most dApps request unlimited approval (the maximum uint256 value: ~1.15 x 10^77). This means the approved contract can drain your entire token balance at any time, even long after you have finished using the dApp.

Approval hygiene

Use revoke.cash or Etherscan's Token Approval Checker to regularly audit and revoke stale approvals. Only approve the exact amount you need when possible. Infinite approvals on compromised or malicious contracts have led to hundreds of millions in losses.

Real-world incident
BadgerDAO exploit (December 2021) -- $120M lost

Attackers compromised Badger's Cloudflare API key and injected malicious scripts into the front-end that prompted users to sign approval transactions to an attacker-controlled address. Users who approved the malicious requests had their tokens drained. The approvals looked like normal dApp interactions.

Reading transaction data

Before signing any transaction, you should understand exactly what it does. Every contract interaction encodes its function call as hexadecimal calldata. The first 4 bytes are the function selector -- the Keccak-256 hash of the function signature, truncated to 4 bytes.

// Common function selectors you should recognize: 0xa9059cbb // transfer(address,uint256) -- sending tokens 0x095ea7b3 // approve(address,uint256) -- granting approval 0x23b872dd // transferFrom(address,address,uint256) -- moving approved tokens 0x39509351 // increaseAllowance(address,uint256) 0xa22cb465 // setApprovalForAll(address,bool) -- NFT approval (dangerous!)

When your hardware wallet shows you raw hex data that you cannot decode, do not sign it. Use tools like Etherscan's input data decoder, the 4byte.directory, or Tenderly's transaction simulator to understand what you are approving.

EIP-712: typed structured data signing

EIP-712 defines a standard for signing typed, structured data off-chain. Unlike raw message signing (eth_sign), EIP-712 presents the data in a human-readable format so you can see exactly what you are signing. This is used by protocols like OpenSea (Seaport orders), Uniswap (Permit2), and many governance systems.

Beware of eth_sign

The eth_sign method signs an arbitrary hash with no context about what the data represents. This is extremely dangerous because an attacker can present a transaction hash for signing, and the signed result can be broadcast as a valid transaction. MetaMask now displays a red warning when a dApp requests eth_sign. Never approve an eth_sign request unless you have verified the exact hash being signed.

Gas: understanding transaction costs

Since EIP-1559 (London upgrade), Ethereum uses a dual-fee model:

  • Base fee: Set by the protocol based on network congestion. This portion is burned.
  • Priority fee (tip): Paid to validators as an incentive to include your transaction.
  • Max fee: The absolute maximum you are willing to pay per unit of gas. Any difference between max fee and (base fee + tip) is refunded.

The formula is: Total cost = gas units used * (base fee + priority fee). A standard ETH transfer costs 21,000 gas units. Complex contract interactions can consume hundreds of thousands or even millions of gas units.

Why are unlimited token approvals considered dangerous?
They cost more gas than limited approvals
They slow down the Ethereum network
They expire after 24 hours, causing failed transactions
The approved contract can drain your entire token balance at any time, even after you stop using the dApp
3

Smart contract risks

Advanced25 min

Reentrancy attacks

Reentrancy is one of the most infamous smart contract vulnerabilities. It occurs when a contract makes an external call to another contract before updating its own state. The receiving contract can then "re-enter" the calling function and repeat the action (e.g., withdraw funds) before the state update occurs.

This is the vulnerability behind the 2016 DAO hack that led to Ethereum's hard fork and the creation of Ethereum Classic.

// VULNERABLE: State updated AFTER external call contract VulnerableVault { mapping(address => uint256) public balances; function withdraw() external { uint256 balance = balances[msg.sender]; require(balance > 0, "No balance"); // External call BEFORE state update -- BUG! (bool success, ) = msg.sender.call{value: balance}(""); require(success, "Transfer failed"); // This line runs AFTER the external call // An attacker's receive() can call withdraw() again // before this line executes balances[msg.sender] = 0; } } // ATTACKER CONTRACT: contract Attacker { VulnerableVault vault; function attack() external payable { vault.deposit{value: 1 ether}(); vault.withdraw(); } receive() external payable { if (address(vault).balance >= 1 ether) { vault.withdraw(); // Re-enter! } } }
// SECURE: Checks-Effects-Interactions pattern contract SecureVault { mapping(address => uint256) public balances; function withdraw() external { uint256 balance = balances[msg.sender]; require(balance > 0, "No balance"); // CHECK balances[msg.sender] = 0; // EFFECT (state update FIRST) (bool success, ) = msg.sender.call{value: balance}(""); require(success, "Transfer failed"); // INTERACTION (external call LAST) } }
Prevention: Checks-Effects-Interactions

Always follow the Checks-Effects-Interactions (CEI) pattern: first validate conditions (Checks), then update state (Effects), then make external calls (Interactions). Additionally, use OpenZeppelin's ReentrancyGuard as a defense-in-depth measure with the nonReentrant modifier.

Integer overflow and underflow

Before Solidity 0.8.0, arithmetic operations did not check for overflow or underflow. A uint256 holding the maximum value (2^256 - 1) would silently wrap around to 0 when incremented. An attacker could exploit this to mint tokens, bypass balance checks, or manipulate accounting logic.

// VULNERABLE (Solidity < 0.8.0): No overflow protection pragma solidity ^0.7.6; contract VulnerableToken { mapping(address => uint256) public balanceOf; function transfer(address to, uint256 value) public { // If balanceOf[msg.sender] is 0 and value is 1: // 0 - 1 underflows to 2^256 - 1 (a massive balance!) balanceOf[msg.sender] -= value; balanceOf[to] += value; } } // SECURE (Solidity >= 0.8.0): Built-in overflow checks pragma solidity ^0.8.20; contract SecureToken { mapping(address => uint256) public balanceOf; function transfer(address to, uint256 value) public { // Solidity 0.8+ automatically reverts on underflow balanceOf[msg.sender] -= value; balanceOf[to] += value; } }

Since Solidity 0.8.0, the compiler includes built-in overflow and underflow checks that automatically revert the transaction. However, developers can bypass these checks using unchecked { } blocks for gas optimization -- which reintroduces the risk if used carelessly.

Access control vulnerabilities

Access control bugs occur when critical functions lack proper authorization checks, allowing unauthorized users to call admin-only functions like mint(), pause(), setFeeRecipient(), or upgradeProxy().

// VULNERABLE: No access control on critical function contract VulnerableVault { address public feeRecipient; // Anyone can call this and redirect all fees to themselves! function setFeeRecipient(address _new) external { feeRecipient = _new; } } // SECURE: Using OpenZeppelin's Ownable import "@openzeppelin/contracts/access/Ownable.sol"; contract SecureVault is Ownable { address public feeRecipient; function setFeeRecipient(address _new) external onlyOwner { feeRecipient = _new; } }
Real-world incident
Parity multi-sig wallet hack (November 2017) -- $150M frozen

A developer accidentally triggered the initWallet() function on the Parity library contract, making themselves the owner. They then called kill(), which self-destructed the library. This permanently froze approximately $150 million in ETH held across 587 wallets that depended on that library contract.

Flash loan attacks

Flash loans allow anyone to borrow an unlimited amount of assets with zero collateral, as long as the loan is repaid within the same transaction. While designed for legitimate arbitrage and liquidation, they dramatically amplify attack vectors:

  • Price oracle manipulation: Borrow massive amounts to move prices on an AMM, exploit a protocol that reads prices from that AMM, then repay the loan -- all in one atomic transaction.
  • Governance attacks: Borrow governance tokens, vote on a malicious proposal, then return the tokens. The attacker never needed to own any tokens.
  • Liquidation cascading: Use flash loans to trigger cascading liquidations and profit from the resulting price impact.
// Simplified flash loan attack flow: // 1. Borrow 1M USDC from Aave (flash loan, no collateral) // 2. Swap 1M USDC for ETH on a small DEX, crashing USDC/ETH price // 3. Target protocol reads price from that DEX (bad oracle!) // 4. Exploit the mispriced position on target protocol // 5. Swap back, repay 1M USDC + 0.09% fee to Aave // 6. Profit: attacker keeps the difference // Total cost to attacker: gas fees only (~$50) // Total profit: potentially millions
Defense: Use Decentralized Oracles

Never use spot AMM prices as price oracles. Use time-weighted average prices (TWAPs), Chainlink price feeds, or other decentralized oracle networks that are resistant to single-transaction manipulation. Protocols like Compound and Aave use Chainlink oracles specifically to prevent flash loan-based price manipulation.

In the vulnerable withdrawal example, what is the correct fix for the reentrancy vulnerability?
Use transfer() instead of call() for sending ETH
Set balances[msg.sender] = 0 before the external call (Checks-Effects-Interactions)
Add a require(msg.sender != address(this)) check
Use a higher gas limit to prevent the callback from executing
What makes flash loans uniquely dangerous for DeFi protocols?
They charge very high interest rates
They can only be repaid in a specific token
Anyone can borrow unlimited amounts with zero collateral, enabling instant price manipulation and governance attacks
They permanently lock tokens in the lending pool
4

Social engineering & phishing

Critical20 min

Fake video call links from hijacked accounts

One of the most effective social engineering attacks in web3 targets trust between colleagues and contacts. Attackers compromise Telegram accounts or email inboxes -- often through SIM swaps, session hijacking, or credential stuffing -- and then use those accounts to send fake Zoom or Google Meet invitations to the victim's contacts. Because the message comes from a known, trusted person, recipients rarely question it.

How the attack works
Step-by-step breakdown
  1. The attacker hijacks a Telegram account or email inbox belonging to someone in the crypto space (founder, developer, investor, team member).
  2. They review recent conversations to identify active deals, collaborations, or ongoing discussions.
  3. They send a message to key contacts: "Hey, can we hop on a quick call? Here's the link" -- referencing a real, ongoing topic to make it convincing.
  4. The link goes to a fake Zoom or Google Meet page (e.g. zoom-us.app, meet.google-web.co, or us06-zoom.us) that prompts the victim to "download an update" or "install a browser plugin" to join.
  5. The download installs malware -- typically an info-stealer that harvests browser cookies, wallet extensions, private keys, and saved passwords.
This attack has caused millions in losses

Multiple crypto founders and investors have lost significant funds to this exact attack. The malware installed through these fake call links often targets MetaMask, Phantom, and other browser-extension wallets, extracting private keys before the victim even realizes their contact's account was compromised.

How to protect yourself

  • Verify through a second channel. If someone sends you a call link on Telegram, confirm via a phone call, Signal, or in person that they actually sent it. Never trust a single channel.
  • Check the URL carefully. Real Zoom links come from zoom.us. Real Google Meet links come from meet.google.com. Any variation (zoom-us.app, meet.google-web.co, us06-zoom.us) is a phishing domain.
  • Never download anything from a call link. Zoom and Google Meet do not require you to install updates or plugins through the meeting link. If you see a download prompt, close the tab immediately.
  • Use the official apps. Open Zoom or Google Meet from the app you already have installed, and paste only the meeting ID -- not the full link from the message.
  • Enable 2FA on everything. Protect your own Telegram and email with hardware-key-based two-factor authentication so you don't become the compromised account used to target others.
Red flags
  • Call link from an unusual domain
  • "Install this update to join"
  • Urgency: "Jump on now, it's about the deal"
  • Contact hasn't mentioned a call before
  • Link sent at an unusual time
Safe practices
  • Verify via phone call before clicking
  • Use bookmarked zoom.us or meet.google.com
  • Never download from meeting links
  • Ask the sender a question only they'd know
  • Keep wallets on a separate device

Fake dApps and cloned websites

Attackers create pixel-perfect replicas of popular DeFi protocols and wallet interfaces. These phishing sites are promoted through Google Ads, social media, and SEO manipulation to appear above legitimate results. When users connect their wallets, the fake dApp prompts them to sign malicious transactions -- typically unlimited token approvals or direct transfers to attacker addresses.

Scenario: fake Uniswap site
uniswapp.org (fake) vs. app.uniswap.org (legitimate)

A user searches "Uniswap" on Google. The top result is a Google Ad pointing to uniswapp.org (note the extra "p"). The site looks identical to real Uniswap. When the user connects their wallet and attempts a swap, the site instead sends an approve() transaction giving the attacker unlimited access to their USDC. The user sees "Swap" in the UI but is actually signing a blank check.

How to verify a dApp is legitimate

  • Bookmark official URLs. Never use search engines to navigate to DeFi protocols. Maintain a personal bookmark list of verified URLs.
  • Check the SSL certificate. Click the lock icon in your browser. Verify the certificate is issued to the correct domain.
  • Verify the contract address. Before signing, check that the contract you are interacting with matches the official deployment address listed in the protocol's documentation or GitHub.
  • Use a transaction simulator. Tools like Tenderly, Blowfish, or Pocket Universe simulate transactions before signing and show you exactly what will happen to your assets.
  • Check the domain age. Phishing domains are usually registered days or hours before the attack. Use WHOIS to check the domain registration date.

Discord scams and social media attacks

Discord is the primary communication hub for most crypto projects, making it a high-value target for attackers. Common attack vectors include:

Compromised server bots

Attackers exploit vulnerable bots or compromise admin accounts to post fake "mint" or "airdrop" announcements in official channels, sending users to phishing sites.

Fake support DMs

Scammers impersonate team members or support staff, DMing users who post questions. They direct victims to "verify their wallet" or "sync" by entering their seed phrase on a fake site.

Webhook hijacking

Attackers compromise Discord webhooks to inject phishing messages that appear to come from official bot accounts, bypassing user suspicion of human-sent messages.

Token-gated traps

Fake "exclusive" Discord servers require users to "connect their wallet to verify holdings." The verification site is actually a phishing page that requests malicious signatures.

Real-world incident
Bored Ape Yacht Club Discord compromise (June 2022)

Attackers compromised the Discord account of a BAYC community manager. They used the account to post a fake "exclusive airdrop" link in the official BAYC Discord server. Users who clicked the link and interacted with the phishing site lost approximately $360,000 in NFTs. The announcement appeared in the official channel from a known moderator, making it highly convincing.

Approval phishing (ice phishing)

Unlike traditional phishing that steals credentials, "ice phishing" (a term coined by Microsoft) tricks users into signing blockchain transactions that grant the attacker permission to move their assets. The attacker never needs your private key or seed phrase -- they just need you to sign one transaction.

The most common forms:

  • ERC-20 approve() to attacker address: The dApp UI shows you are interacting with a legitimate protocol, but the actual transaction calls approve(attacker_address, MAX_UINT) on your token contract.
  • setApprovalForAll() for NFTs: A single signature grants the attacker control over your entire NFT collection from a given contract.
  • Permit signature (ERC-2612): A gasless off-chain signature that grants a token allowance. The attacker can later submit this signature to move your tokens without you ever seeing an on-chain transaction until it is too late.
  • Seaport/Marketplace listings: A malicious site tricks you into signing an OpenSea Seaport order that lists your valuable NFTs for 0 ETH, which the attacker immediately fills.
Permit Signatures are Invisible

ERC-2612 Permit signatures are particularly dangerous because they are off-chain. The victim signs a message (no gas cost, no on-chain trace), and the attacker submits the permit on-chain later to drain tokens. The victim may not realize anything happened until they check their balance. Always scrutinize any signature request, even if it does not cost gas.

Red flags to watch for

  • A website asks you to "verify your wallet" or "sync" -- legitimate protocols never require this.
  • A signature request shows an unfamiliar contract address or one that does not match the official deployment.
  • You receive an unsolicited airdrop of unknown tokens. Interacting with them (even trying to sell) can trigger a malicious contract.
  • A "support" agent DMs you first. Real support teams almost never initiate direct messages.
  • Time pressure: "Only 100 spots left!" or "Mint closes in 5 minutes!" -- urgency is the attacker's best tool.
  • The MetaMask popup shows eth_sign instead of a structured data request.
  • You are asked to sign something to "claim" tokens from a project you did not interact with.
How does "ice phishing" differ from traditional phishing?
It steals your seed phrase through a fake wallet recovery page
It tricks you into signing a transaction that grants the attacker permission to move your assets, without ever stealing your private key
It installs malware on your hardware wallet
It intercepts your transactions on the blockchain before they are confirmed
What is the most effective way to avoid interacting with a fake (phishing) dApp?
Bookmark official URLs and always navigate using your bookmarks instead of search engines
Only use dApps that appear on the first page of Google results
Check if the website has a professional design
Use incognito mode in your browser
5

Organizational security

Essential20 min

Multi-signature wallet setup

A multi-signature (multi-sig) wallet requires M-of-N signatures to approve any transaction. For example, a 3-of-5 setup means any 3 of the 5 designated signers must approve before a transaction can execute. This eliminates single points of failure and protects against compromised keys, rogue insiders, and coercion.

Recommended configurations by treasury size:

Treasury SizeConfigurationReasoning
< $100K2-of-3Basic protection while maintaining operational speed
$100K - $1M3-of-5Balances security with availability; can tolerate 2 unavailable signers
$1M - $10M4-of-7Higher threshold for larger amounts; geographic distribution of signers
> $10M5-of-9 + TimelockMaximum security with mandatory time delay on execution
Safe{Wallet} (formerly Gnosis Safe)

Safe is the industry standard for multi-sig wallets, securing over $100 billion in digital assets. It supports EVM-compatible chains, transaction batching, spending policies, and integration with governance frameworks like Snapshot and Zodiac. Always deploy Safe through the official app at app.safe.global.

Signer selection best practices

  • Geographic distribution: Signers should be in different physical locations to prevent a single physical event (fire, raid, natural disaster) from compromising the quorum.
  • Hardware wallets required: Every signer must use a hardware wallet. No exceptions. Software wallets are too vulnerable to malware, phishing, and device compromise.
  • Diverse device types: Use a mix of Ledger and Trezor devices to avoid single-vendor supply chain risk.
  • Clear role definitions: Document who each signer is, their role, their backup contact, and the procedure for replacing them if they leave the organization.
  • Regular verification: Monthly signing exercises to ensure all signers can still access their keys and devices are functional.

Key management policies

Every organization handling digital assets needs a formal key management policy. This document should cover the full lifecycle of cryptographic keys from generation through destruction.

Key generation

Generate keys on air-gapped devices. Use hardware wallet secure elements. Never generate keys on internet-connected computers or through web interfaces.

Key storage

Primary key in hardware wallet. Seed phrase backup on steel plates in geographically separate fireproof safes. No digital copies, no cloud storage, no photographs.

Key rotation

Rotate signer keys quarterly or when any signer departs. Update multi-sig configurations promptly. Old signers should never retain access to active wallets.

Key destruction

When keys are decommissioned: reset hardware wallets to factory settings, destroy steel plate backups physically. Document the destruction with witnesses.

The bus factor

Ask yourself: "How many people could be unavailable (quit, get sick, lose their device) before we can no longer access our funds?" This is your "bus factor." If the answer is 1, you have a critical single point of failure. Your multi-sig threshold must always be lower than the total number of signers by at least 2.

Security policies and procedures

Written, enforced security policies are the backbone of organizational security. They transform ad-hoc decisions into consistent, auditable processes. The following policies should be documented, reviewed quarterly, and signed by all team members:

  • Transaction approval policy: Define thresholds. For example: transactions under $1K require 2 signatures; $1K-$50K require 3 signatures + 24-hour timelock; above $50K require 4 signatures + 48-hour timelock + verification call between signers.
  • Smart contract interaction policy: Whitelist approved contracts and protocols. Any interaction with a new contract requires security review by at least 2 team members, contract verification on Etherscan, and a test transaction with minimal funds.
  • Communication security: Use end-to-end encrypted channels (Signal) for sensitive discussions. Never discuss private keys, seed phrases, or transaction details on Discord, Telegram, or email. Verify all signer identities through a separate channel before approving large transactions.
  • Device security: Mandatory full-disk encryption on all devices. Hardware wallets stored in secure locations when not in use. Separate "hot" devices for daily operations from "cold" devices used only for signing.
  • Access control: Principle of least privilege. Team members only have access to the systems and wallets necessary for their role. No shared accounts. All access is logged and auditable.

Incident response plan

When a security incident occurs -- a compromised key, a detected exploit, or suspicious activity -- every second counts. A well-rehearsed incident response plan can mean the difference between a minor scare and a catastrophic loss.

The 5-phase framework

  1. Detection and Alerting (0-5 minutes):

    Set up on-chain monitoring (Tenderly, Forta, OpenZeppelin Defender) to detect unusual transactions. Define alert thresholds: any transaction above $X, any interaction with non-whitelisted contracts, any owner change. All alerts go to a dedicated Slack/Signal channel that team members actively monitor.

  2. Containment (5-30 minutes):

    Immediately pause affected contracts if possible (if you have a pause() function). Revoke compromised key access from multi-sig. Move assets from compromised wallets to secure backup wallets. Disable affected API keys and access tokens.

  3. Assessment (30 minutes - 2 hours):

    Determine the scope: What was compromised? How? What is the potential financial impact? Preserve all evidence: logs, transaction hashes, screenshots, timeline. Do not modify or clean up systems before evidence is collected.

  4. Recovery (2-48 hours):

    Deploy new keys and wallets. Migrate assets through verified secure channels. Update all dependent systems with new addresses and configurations. Perform full security audit of all related systems before resuming normal operations.

  5. Post-Mortem (Within 1 week):

    Conduct a blameless post-mortem. Document the full timeline, root cause, impact, and response effectiveness. Identify policy gaps and implement improvements. Share findings with the broader team. Update the incident response plan based on lessons learned.

Practice Makes Prepared

Run incident response drills at least quarterly. Simulate scenarios like "Signer 2's hardware wallet is compromised" or "Our hot wallet is draining." Time the response. Identify bottlenecks. An untested plan is barely better than no plan.

For a company treasury holding $500K in digital assets, what multi-sig configuration is recommended and why?
1-of-1 (single key) for maximum speed and efficiency
5-of-5 for maximum security since all signers must agree
3-of-5, because it prevents single-key compromise while tolerating 2 unavailable signers
2-of-2 because you only need two people for security
During an active security incident, what is the first action after detection?
Post a public announcement explaining the situation
Containment: pause affected contracts, revoke compromised keys, move at-risk assets to secure wallets
Wait 24 hours to fully assess the scope before taking action
Contact law enforcement and wait for their instructions

Continue your security journey

Deepen your knowledge with our in-depth guides covering multi-sig wallet setup, smart contract auditing best practices, and real-world phishing case studies.