ByAUJay
“Is Walletconnect Safe” vs “Is Wallet Connect Safe”: WalletConnect Security Best Practices Documentation
Summary: WalletConnect v2 is a secure, end‑to‑end encrypted transport for wallet–app messaging, but your security outcome depends on how you scope permissions, verify domains, and design UX around signing. This guide translates the latest WalletConnect specs and incidents into concrete controls for startups and enterprises.
TL;DR for decision‑makers
- WalletConnect v2 encrypts messages end‑to‑end (X25519 + HKDF + ChaCha20‑Poly1305) and authenticates clients with Ed25519 DIDs; the relay only sees topics, tags, and TTLs—not your payloads. That’s strong transport security, not app‑level trust. (specs.walletconnect.com)
- V1 is shut down (since June 28, 2023). If you still see a wc:@1 QR link, treat it as unsafe and migrate to v2 immediately. (walletconnect.com)
- Most losses come from phishing/drainers via malicious front‑ends or fake apps, not protocol breaks. Use Verify API domain attestation in wallets and register your dapp domain so wallets can warn/block. (docs.walletconnect.network)
- Scope sessions tightly (CAIP‑2 chains, CAIP‑10 accounts, explicit method allowlists), prefer typed data (EIP‑712), and set short expiries with business‑appropriate exceptions (up to 7 days) for institutional sign‑off flows. (specs.walletconnect.com)
- Harden mobile linking and UX: prefer deep links over universal links, avoid redirect metadata abuse, and consider Link Mode to reduce latency and brittle WebSocket dependence on spotty networks. (docs.walletconnect.network)
Part 1 — What WalletConnect secures (and what it doesn’t)
WalletConnect is a chain‑agnostic, topic‑based, pub/sub messaging layer that delivers encrypted JSON‑RPC between a wallet and an app (dapp). The relayer stores/caches only encrypted messages until TTL expiry; identity is a DID derived from an Ed25519 keypair and authenticated to the relay with a signed JWT. In transit, session key agreement uses X25519, with symmetric keys derived via HKDF and payloads sealed with ChaCha20‑Poly1305. (specs.walletconnect.com)
What this means:
- The relay operator cannot read your messages or infer account addresses from payloads. It sees topics, tags, TTLs, and user‑agent hints for diagnostics. (specs.walletconnect.com)
- Messages persist server‑side only until the configured TTL; common tags/TTLs are defined per RPC (e.g., 300s for wc_sessionRequest, 86400s for session updates). (specs.walletconnect.com)
- WalletConnect is not a transaction firewall. If a user approves a malicious request, the signature is valid. Mitigations must live in your permissions, domain verification, and UX. (docs.walletconnect.network)
Note on network operations and decentralization: As of 2025, WalletConnect describes a network with service and gateway nodes and an ongoing decentralization roadmap, with public comms about WCN 2.0 and third‑party operators. Treat these as performance/resilience improvements—not changes to the E2E security model. (docs.walletconnect.network)
Part 2 — v1 vs v2: why the difference matters
- v1 used bridge servers and a different URI schema; it is decommissioned. Continuing to use v1 URIs (wc:…@1?bridge=…) is operationally risky and non‑supported. Migrate to v2 URIs (wc:…@2?symKey=…&relay-protocol=irn&methods=…). (walletconnect.com)
- v2 introduces Namespaces (CAIP‑2/CAIP‑10) and explicit permissioning of chains/methods/events at session proposal time—your primary lever to reduce blast radius. (specs.walletconnect.com)
Example of a secure, minimal v2 proposal for an EVM‑only read/write dapp on Ethereum mainnet:
{ "requiredNamespaces": { "eip155": { "chains": ["eip155:1"], "methods": [ "eth_sendTransaction", "eth_signTypedData" ], "events": ["chainChanged", "accountsChanged"] } }, "optionalNamespaces": {} }
Namespacing rules are strict—chains must be CAIP‑2 compliant and session accounts must be CAIP‑10 compliant. Enforce these validations in your client. (specs.walletconnect.com)
Part 3 — Real‑world threats and what they teach us
-
Supply‑chain injection via third‑party connectors (Dec 14, 2023)
A malicious Ledger Connect Kit version was published on npm/CDN, injecting a drainer into many dapps. It exploited blind/ambiguous signing prompts to trick users—not a WalletConnect cryptography issue. Ledger rolled out a fixed kit, Tether froze assets, and Ledger committed to sunsetting blind signing. Lesson: don’t rely on library trust alone; hard‑fail on domain mismatches and ban unsafe signing methods. (ledger.com) -
Fake “WalletConnect” mobile apps (Sept 2024)
Scammers placed a fake “WalletConnect” app on Google Play that drained ~$70k. WalletConnect reminded users there is no official “WalletConnect” wallet app. Lesson: educate users, and in wallets/dapps, display verified brand metadata and Verify API status prominently. (thecoinrepublic.com) -
Implementation gaps
Ecosystem wallets may lag parts of the spec (e.g., historical optional namespaces support issues). Don’t assume optional UX features work uniformly; code defensively and detect feature support at runtime. (github.com)
Part 4 — Controls you should implement today
4.1 Session scoping and permissions
- Request only the chains you truly need (CAIP‑2) and only signable methods you truly use; reject everything else by default at the wallet layer. (specs.walletconnect.com)
- Prefer EIP‑712 typed data (eth_signTypedData/…v4) for off‑chain auth and permissions; avoid raw
which is ambiguous and often used in drainers. (eips.ethereum.org)eth_sign - Set sane expiries for each session request. By spec, MIN 5 minutes and MAX 7 days. For consumer UX, default to minutes; for custody MPC/after‑hours approval flows, extend with explicit UI. (specs.walletconnect.com)
Code pattern for a narrowly‑scoped, expiring request:
// send a typed data signature request with 10-minute expiry signClient.request({ topic, chainId: "eip155:1", request: { method: "eth_signTypedData", params: [address, typedData], expiry: Math.floor(Date.now()/1000) + 600 } });
TTLs for relay publish should align with your expiry; increase if needed so the relay caches the message long enough for the user to respond. (specs.walletconnect.com)
4.2 Domain verification and phishing defenses
- If you are a wallet: integrate Verify API and surface one of four states (VALID, UNVERIFIED, MISMATCH, THREAT), backed by a domain registry and threat feeds. Block or warn on mismatches/threats. (docs.walletconnect.network)
- If you are a dapp: register your trusted domains so wallets can attest them, and ensure your app.metadata.url matches your canonical domain. (walletconnect.com)
Pseudo‑UX:
walletKit.on("verify_context", (ctx) => { switch (ctx.status) { case "VALID": showGreenBanner(appUrl); break; case "UNVERIFIED": showNeutralBanner(appUrl); break; case "MISMATCH": block("Domain mismatch"); break; case "THREAT": hardBlock("Known malicious domain"); break; } });
4.3 Safer authentication
- Use WalletConnect’s Auth flow (wc_sessionAuthenticate) with SIWE (EIP‑4361) and CACAO (CAIP‑74) to bind identity to a domain and requested capabilities. This enables “one‑click auth” and reduces phishing by showing a wallet‑parsed summary. (specs.walletconnect.com)
- Scope SIWE messages tightly: domain, statement, nonce, chainId, and expiry. Avoid open‑ended “sign to continue” prompts. (eips.ethereum.org)
4.4 Mobile linking hygiene
- Prefer deep links over universal links to minimize browser detours. Do not auto‑redirect users based on QR‑scan metadata; that can misroute to the wrong app. (docs.walletconnect.network)
- For native dapp ↔ native wallet, enable Link Mode to ship session/auth requests over universal/app links when WebSockets are flaky—improving reliability and latency. (docs.walletconnect.network)
- Ensure the wallet returns users to the originating app after approve/reject, and ignore incomplete URIs used only to wake the wallet. (docs.walletconnect.network)
4.5 Transport, observability, and SLOs
- Monitor relay connectivity and latency; WalletConnect best practices suggest <5s connect/sign in normal networks, <15s on poor networks. Instrument relayer_connect/relayer_disconnect events. (docs.walletconnect.network)
- For regulated/institutional stacks, use extended request expiries (up to 7 days) with clear pending/timeout UX and audit trails. (docs.walletconnect.network)
4.6 Banning dangerous methods and patterns
- Ban or gate
and legacy personal message signing for anything security‑sensitive; prefer EIP‑712. (eips.ethereum.org)eth_sign - Never request wallet‑wide permissions; enumerate contract addresses and methods you actually call. Document this in your session proposal UX so users understand exactly what’s being granted. (specs.walletconnect.com)
Part 5 — Designing a secure WalletConnect session (end‑to‑end)
-
Pairing and URI
v2 pairings use the wc: URI with required parameters: symKey, methods, relay‑protocol (typically irn), and optional expiryTimestamp. Example format:
(specs.walletconnect.com)wc:<topic>@2?symKey=<hex>&methods=[wc_sessionPropose],[wc_authRequest,wc_authBatchRequest]&relay-protocol=irn&expiryTimestamp=<unix> -
Session proposal
Send only requiredNamespaces; avoid optionalNamespaces unless your target wallets support them. Validate returned sessionNamespaces strictly: accounts must be CAIP‑10; chain prefixes must match. (specs.walletconnect.com) -
Authentication (optional but recommended)
Use wc_sessionAuthenticate (CACAO) to bind the user’s address to your domain and requested capabilities before any state‑changing call. Respect expiry semantics: 5 minutes to 7 days. (specs.walletconnect.com) -
Requests
For each wc_sessionRequest, set an expiry aligned to your UX; ensure relay TTL covers that window. Wallets must reject requests whose method/chain weren’t approved in the session. (specs.walletconnect.com) -
Events and lifecycle
Handle session_expire and proposal_expire cleanly; allow users to extend or delete sessions (wc_sessionExtend/wc_sessionDelete). This prevents “zombie” permissions. (specs.walletconnect.com)
Part 6 — Practical examples you can lift into production
Example A — Minimal EIP‑712 signing flow with domain verification
// 1) Propose a minimal session on mainnet const proposal = { requiredNamespaces: { eip155: { chains: ["eip155:1"], methods: ["eth_signTypedData"], events: ["chainChanged", "accountsChanged"] } } }; // 2) After approval, verify domain context (wallet side) walletKit.on("verify_context", (ctx) => { if (ctx.status === "MISMATCH" || ctx.status === "THREAT") { return showBlocker("Unsafe domain"); } }); // 3) Send a typed-data request with short expiry await signClient.request({ topic, chainId: "eip155:1", request: { method: "eth_signTypedData", params: [userAddress, typedData], expiry: Math.floor(Date.now()/1000) + 300 // 5 minutes } });
Why this is safer: tight chain/method scope, typed data with domain separation (EIP‑712), short expiry, and explicit domain verification. (eips.ethereum.org)
Example B — Institutional approval flow with extended expiry
Use extended expiry for off‑hours co‑signing or custody approvals (up to 7 days). Wallet UX should surface countdowns and re‑validate intent at sign time.
await signClient.request({ topic, chainId: "eip155:1", request: { method: "eth_sendTransaction", params: [tx], expiry: Math.floor(Date.now()/1000) + 172800 // 48 hours } }); // relay TTL must be >= expiry window
Spec constraints: MIN 5 minutes, MAX 7 days. Wallet must discard expired requests and return a specific “request expired” error. (specs.walletconnect.com)
Example C — Mobile‑first reliability with Link Mode
If your native dapp serves commuters on flaky networks, enable Link Mode so session/auth requests travel over app/universal links instead of requiring a live WebSocket to the relay. This cuts perceived latency and reduces drop‑offs. (docs.walletconnect.network)
Part 7 — Governance, hosting, and operational reality
- Self‑hosting the v2 relay isn’t generally supported as a production option per the archived reference repo; rely on the WalletConnect Network and published SLAs while decentralization expands. (github.com)
- WalletConnect publishes relay APIs, TTLs, and webhook semantics. If you integrate watchdogs, sign and verify webhook events and cap retries per spec. (specs.walletconnect.com)
Part 8 — UX standards and ecosystem signals
- WalletConnect Certified and WalletGuide surface wallets with stricter UX/security baselines. Favor Certified wallets for enterprise rollouts and document supported features (Verify API, Link Mode, SIWE, multi‑chain). (walletconnect.com)
- If your users ask for a “WalletConnect app,” educate them: WalletConnect is a protocol; choose a reputable wallet and connect only from the wallet’s in‑app scanner or a verified dapp domain. This advice follows real fake‑app incidents. (thecoinrepublic.com)
Part 9 — Security checklist (copy/paste into your runbook)
- Protocol/version
- Block v1; accept only wc:@2 URIs. (walletconnect.com)
- Permissions
- CAIP‑2 chains: list exact networks; no wildcards.
- Methods: allowlist only what you call; ban
. (specs.walletconnect.com)eth_sign
- Authentication
- Use wc_sessionAuthenticate with SIWE; bind to your domain. (specs.walletconnect.com)
- Expiries
- Set short expiries by default; extend only for custody flows (≤7 days). Align relay TTL. (specs.walletconnect.com)
- Domain verification
- Register your domain; wallets: integrate Verify API and block MISMATCH/THREAT. (docs.walletconnect.network)
- Mobile linking
- Prefer deep links; avoid redirect metadata on QR scans; consider Link Mode. (docs.walletconnect.network)
- Observability
- Monitor relayer_connect/relayer_disconnect; track connect/sign latency against <5s/<15s SLOs. (docs.walletconnect.network)
- User education
- No “WalletConnect app”; connect from verified dapps only; warn on blind signing. (thecoinrepublic.com)
- Supply chain
- Pin and monitor third‑party kits; verify integrity; fail closed on unexpected prompts. (ledger.com)
Part 10 — FAQ: “Is Walletconnect Safe” vs “Is Wallet Connect Safe”
- It’s the same thing—people search both spellings. The real question is whether your implementation is safe. WalletConnect v2’s crypto and relay model are robust, but your risk stems from session scope, domain verification, signing UX, and library supply chains. Follow the controls in this document. (specs.walletconnect.com)
Appendix — Reference snippets and specs
- WalletConnect v2 pairing URI and parameters (symKey, methods, relay‑protocol, expiryTimestamp). (specs.walletconnect.com)
- Namespaces and CAIP compliance for chains/accounts. (specs.walletconnect.com)
- RPC TTLs and expiry ranges for session methods (e.g., wc_sessionRequest). (specs.walletconnect.com)
- EIP‑712 typed data spec. (eips.ethereum.org)
Bottom line for startups and enterprises
WalletConnect is safe when you treat it as a secure transport inside a defense‑in‑depth program. If you lock down namespaces and methods, verify domains, default to typed data, time‑box signing windows, and harden mobile linking, you dramatically cut drainer/phishing risk while preserving UX. The protocol won’t save you from poor app decisions—but it gives you all the hooks you need to build a safe, scalable onchain product. (specs.walletconnect.com)
Like what you're reading? Let's build together.
Get a free 30‑minute consultation with our engineering team.

