From ecd6409b88552aca355b89b626f1ea721cc5af20 Mon Sep 17 00:00:00 2001 From: candyburst Date: Sun, 31 May 2026 19:48:55 +0530 Subject: [PATCH] security: add domain validation to SIWE authentication examples Fixes cross-domain replay attack vulnerability in authenticate-users guide. ## Problem Backend examples only verified cryptographic signature without validating the SIWE message domain. This allows valid signatures from evil.com to be replayed against yourapp.com's /auth/verify endpoint. ## Changes - Replace `verifyMessage` with `verifySiweMessage` in both examples - Add explicit domain parameter validation - Add comment explaining security rationale - Import `verifySiweMessage` from 'viem/siwe' ## Impact Prevents cross-domain replay attacks as required by EIP-4361 spec. Developers following this guide will now ship secure authentication. Fixes #1502 Co-Authored-By: Claude Opus 4.7 (1M context) --- .../guides/authenticate-users.mdx | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/docs/base-account/guides/authenticate-users.mdx b/docs/base-account/guides/authenticate-users.mdx index 7a8332200..5658dab32 100644 --- a/docs/base-account/guides/authenticate-users.mdx +++ b/docs/base-account/guides/authenticate-users.mdx @@ -146,13 +146,22 @@ try { ``` ```ts Backend (Viem) import { createPublicClient, http } from 'viem'; +import { verifySiweMessage } from 'viem/siwe'; import { base } from 'viem/chains'; const client = createPublicClient({ chain: base, transport: http() }); export async function verifySig(req, res) { const { address, message, signature } = req.body; - const valid = await client.verifyMessage({ address, message, signature }); + + // Verify SIWE message with domain validation + const valid = await verifySiweMessage(client, { + address, + message, + signature, + domain: 'yourapp.com', // Replace with your actual domain + }); + if (!valid) return res.status(401).json({ error: 'Invalid signature' }); // create session / JWT res.json({ ok: true }); @@ -184,6 +193,7 @@ export async function verifySig(req, res) { import crypto from "crypto"; import express from "express"; import { createPublicClient, http } from "viem"; +import { verifySiweMessage } from "viem/siwe"; import { base } from "viem/chains"; const app = express(); @@ -209,8 +219,15 @@ app.post("/auth/verify", async (req, res) => { return res.status(400).json({ error: "Invalid or reused nonce" }); } - // 2. Verify signature - const valid = await client.verifyMessage({ address, message, signature }); + // 2. Verify SIWE signature with domain validation (prevents cross-domain replay attacks) + const valid = await verifySiweMessage(client, { + address, + message, + signature, + domain: 'yourapp.com', // Replace with your actual domain + nonce, // verifySiweMessage validates nonce is in the message + }); + if (!valid) return res.status(401).json({ error: "Invalid signature" }); // 3. Create session / JWT here