One of the most common security vulnerabilities I see in web dApp assessments is relying on signed messages (i.e., personal_sign) for authentication.
Web3 dApps often use personal_sign for authentication, assuming it’s secure because only the owner of the wallet can sign messages. But what if attackers trick users into signing something they shouldn’t from a fake site?
The Risk:
An attacker can phish a signature from a user and reuse it to impersonate them, transfer offchain assets to a new onchain wallet, or execute layer-2 transactions—without needing their private key.
Actual Findings:
- The ability to phish admin account signatures to access their cloud hosted airdrop portal for unauthorized minting of assets.
- The ability to takeover player accounts and their in-game NFT assets.
How to Fix It:
- Require two-factor auth for sensitive state changing actions
- Implement strict CORS policies to prevent phishing attempts
- Require domain-bound signatures (EIP-4361: Sign-In with Ethereum)
- Use a nonce in signed message requests to prevent replay attacks
**The risks vary depending on if you're operating on a layer 2 protocol, use a Web2 backend, or are using pure web3 infra without a backend.
If your dApp uses personal_sign, how do you prevent signature reuse?