Smart contracts aren't the weakest link anymore — your team is.
In Q1 2026, DeFi protocols lost over $135 million to hacks. But here's the uncomfortable truth: the majority of these losses had nothing to do with smart contract bugs. Step Finance ($40M), the Trezor social engineering attack ($282M in BTC/LTC), and several other incidents all traced back to operational security failures — compromised devices, leaked keys, and inadequate access controls.
As a security researcher who's audited lending protocols, DEXs, and cross-chain bridges, I've compiled the 7 most critical operational security practices that could have prevented these incidents.
1. Kill the Single-Signer Treasury
The Problem: Step Finance's entire treasury — 261,854 SOL — was drained because executive devices with direct access to treasury wallets were compromised. One compromised device = total loss.
The Fix:
# Bad: Single EOA controlling treasury
Treasury → Single Private Key → Executive's Laptop
# Good: Multisig with distributed signers
Treasury → Gnosis Safe (3-of-5)
├── Signer 1: Hardware wallet (CEO) — Location A
├── Signer 2: Hardware wallet (CTO) — Location B
├── Signer 3: Hardware wallet (Security Lead) — Location C
├── Signer 4: Hardware wallet (Board Member) — Cold storage
└── Signer 5: Hardware wallet (Legal) — Vault
Key rules:
- Minimum 3-of-5 threshold for treasuries over $1M
- Never N-of-N (losing one key = permanent fund loss)
- Each signer uses a dedicated hardware wallet purchased directly from manufacturer
- Signers must be in different physical locations
- No signer's key should have ever touched a hot wallet
2. Implement Timelocks on Everything Critical
Timelocks are your safety net. Even if an attacker compromises enough signers, a timelock gives your team and community time to react.
// Solidity: OpenZeppelin TimelockController pattern
contract ProtocolGovernance {
uint256 public constant TIMELOCK_DELAY = 48 hours;
mapping(bytes32 => uint256) public pendingActions;
function scheduleUpgrade(address newImpl) external onlyMultisig {
bytes32 actionId = keccak256(abi.encode("upgrade", newImpl));
pendingActions[actionId] = block.timestamp + TIMELOCK_DELAY;
emit UpgradeScheduled(newImpl, block.timestamp + TIMELOCK_DELAY);
}
function executeUpgrade(address newImpl) external onlyMultisig {
bytes32 actionId = keccak256(abi.encode("upgrade", newImpl));
require(
pendingActions[actionId] != 0 &&
block.timestamp >= pendingActions[actionId],
"Timelock not expired"
);
// Execute upgrade...
}
}
// Anchor (Solana): Timelock pattern
#[account]
pub struct TimelockAction {
pub action_type: ActionType,
pub execute_after: i64, // Unix timestamp
pub proposer: Pubkey,
pub executed: bool,
}
pub fn propose_action(ctx: Context<ProposeAction>, action: ActionType) -> Result<()> {
let timelock = &mut ctx.accounts.timelock_action;
let clock = Clock::get()?;
timelock.action_type = action;
timelock.execute_after = clock.unix_timestamp + DELAY_SECONDS;
timelock.proposer = ctx.accounts.authority.key();
timelock.executed = false;
emit!(ActionProposed { action, execute_after: timelock.execute_after });
Ok(())
}
Recommended delays:
| Action | Minimum Delay |
|--------|--------------|
| Contract upgrade | 48 hours |
| Treasury withdrawal > $100K | 24 hours |
| Admin role change | 72 hours |
| Emergency pause | 0 (immediate) |
| Emergency unpause | 24 hours |
3. Dedicated Signing Devices — No Exceptions
The Step Finance team's personal/work devices were compromised. This is a predictable failure mode.
The Protocol:
- Buy a dedicated laptop for transaction signing — never use it for email, browsing, or Slack
- Hardware wallet only — Ledger or Trezor, purchased from official store
- Air-gapped signing for transactions > $50K: generate the transaction on your main machine, transfer via QR code or USB to the signing device
- Wipe and rebuild signing devices every 90 days
- Never install messaging apps, browsers, or any software beyond what's needed for signing
# Minimal signing workstation setup (Ubuntu)
# Only install: wallet software, verification tools
sudo apt install -y gnupg2 curl
# NO: slack, discord, telegram, chrome, firefox
# Firewall: block all outbound except specific RPC endpoints
sudo ufw default deny outgoing
sudo ufw allow out to 1.2.3.4 port 443 # Your RPC only
sudo ufw enable
4. Supply Chain Security for Smart Contracts
Three protocols in early 2026 were compromised through their build pipelines — not their source code. SagaEVM lost $7M from inherited precompile vulnerabilities.
Checklist:
- [ ] Pin all dependencies to exact versions (no
^or~) - [ ] Verify compiler checksums before every build
- [ ] Use deterministic builds — same source = same bytecode, always
- [ ] Audit your CI/CD pipeline as rigorously as your contracts
- [ ] Two-person review for any dependency update
- [ ] Monitor
npm audit/cargo auditin CI
# Foundry: Pin everything in foundry.toml
[profile.default]
solc_version = "0.8.24" # Exact version, not ">=0.8.0"
optimizer = true
optimizer_runs = 200
# Lock remappings to specific commits
[dependencies]
openzeppelin = { version = "5.0.2", git = "https://github.com/OpenZeppelin/openzeppelin-contracts", rev = "abc1234" }
# Anchor: Pin in Cargo.toml
[dependencies]
anchor-lang = "=0.30.1" # Exact version
anchor-spl = "=0.30.1"
solana-program = "=1.18.26"
5. Real-Time Monitoring and Circuit Breakers
If Step Finance had monitoring that detected the first unauthorized transfer, they could have paused the remaining wallets. Instead, all were drained in sequence.
Must-have alerts:
- Any treasury transaction above threshold
- Multiple transactions within a short window
- Transactions from new/unknown addresses
- Failed multisig attempts
- Contract upgrade proposals
# Simple monitoring script (production would use Forta/OpenZeppelin Defender)
import asyncio
from solders.pubkey import Pubkey
from solana.rpc.websocket_api import connect
TREASURY = Pubkey.from_string("YourTreasuryAddress...")
ALERT_THRESHOLD_SOL = 1000
async def monitor_treasury():
async with connect("wss://api.mainnet-beta.solana.com") as ws:
await ws.account_subscribe(TREASURY)
async for msg in ws:
balance_change = parse_balance_change(msg)
if abs(balance_change) > ALERT_THRESHOLD_SOL:
await send_alert(
f"🚨 CRITICAL: Treasury balance changed by "
f"{balance_change} SOL. Investigate immediately!"
)
if balance_change < -ALERT_THRESHOLD_SOL:
await trigger_emergency_pause()
Tools to use:
- EVM: OpenZeppelin Defender, Forta Network, Tenderly Alerts
- Solana: Helius Webhooks, custom RPC subscriptions, Clockwork automation
- Cross-chain: Chainalysis KYT, Elliptic
6. Incident Response Plan — Write It Before You Need It
Most teams scramble during a hack. The ones that recover have a plan ready.
Your IR document should cover:
## Incident Response Runbook
### Detection
- Who monitors alerts? (Named individuals, not "the team")
- What's the escalation path? (PagerDuty, Signal group, NOT Discord)
### Containment (first 15 minutes)
1. Pause all contracts (who has pause authority?)
2. Revoke compromised keys
3. Contact bridge operators to freeze funds
4. Alert exchanges (have contacts pre-established)
### Communication
- Template post for Twitter/Discord (pre-written)
- Legal counsel contact (pre-engaged)
- Law enforcement contacts (FBI IC3, local cyber units)
### Recovery
- Backup multisig procedure
- Fund recovery process
- Post-mortem timeline
7. Regular Security Drills
Run simulated attacks quarterly. Not tabletop exercises — actual red team operations.
Drill scenarios:
- Compromised signer: One team member's key is "stolen" — can the team rotate it within 2 hours?
- Malicious upgrade: A fake contract upgrade is proposed — does anyone catch it before timelock expires?
- Phishing attack: Send realistic phishing emails to your team — who clicks?
- Key rotation: Can your team perform a full key rotation under pressure without losing access?
Track metrics:
- Time to detect the simulated attack
- Time to contain
- Number of team members who fell for phishing
- Whether emergency procedures were followed correctly
The Bottom Line
In 2026, the math is clear: access control failures caused more losses than smart contract bugs. The most audited code in the world won't save you if your CTO's laptop is compromised and it has direct access to your treasury.
Security isn't just code review — it's operational discipline.
DreamWork Security researches DeFi vulnerabilities and publishes security tools for the Web3 community. Follow for weekly security deep dives.
Previous articles in this series:
Top comments (0)