Important Disclaimer / Confidentiality
The advisory was responsibly disclosed to all known users of SIW* on July 1st, 2025. It is now made available for everyone since the embargo period of 90 days has ended.
TL;DR
The IC-SIW* implementations allow ICP users to sign into dapps using wallets like Metamask, Phantom, etc. Unfortunately, many of these login flows are prone to phishing attacks, where a malicious entity may gain control over a victim’s identity. This advisory publicly discloses the phishing issue, assesses the risk, and gives recommendations for hardening security.
Given the high risk, it is strongly recommended that users of IC-SIW* harden their implementations against phishing, along the lines of the recommendations in this advisory.
Introduction
The IC-SIW* (ic-siwb, ic-siwe, ic-siws) implementations allow ICP users to sign into dapps using their wallet for another blockchain by signing a specific message using that wallet. An ICP principal is derived from the external wallet address/public key which only the wallet owner will have access to. This proof of possession is provided by the signature.
Specifically, the IC-SIW* standard follows this general implementation:
- The IdP canister exposes prepare_login, login and get_delegation methods
- The user (frontend) initiates the login by calling prepare_login. The canister returns a message compatible with the SIW* standard of the respective ecosystem.
- The message needs to be signed by the user’s wallet on the other blockchain network.
- The signed message is sent by the frontend to the canister’s login function.
- The IdP canister verifies the signature and checks if the public key retrieved is the one used during prepare_login.
- If successful, the canister generates a new delegation for the user.
- The user can retrieve the delegation via get_delegation and sign messages in the IC with a principal bound to the wallet address.
Issue
IC-SIWB, IC-SIWE, and IC-SIWS all take a similar approach: they map an external crypto wallet address to an ICP principal, regardless of which website (e.g. an ICP dapp) requested the sign-in. This results in a shared identity across different origins (e.g. domains of ICP dapps) for the same user.
This is like using “Login with Google” but if you do it, you get access to any other app where the user logs in with Google, strongly violating a user’s security expectations. This opens the door to Phishing attacks, as we explain in the following.
On ICP, Internet Identity adopts a per-dapp identity model, which enhances privacy and security for the end user. In this model, a user receives a different principal depending on the origin (i.e., the domain) of the dapp requesting the sign-in. As a result, dApps cannot correlate user behavior across different dapps. Additionally, malicious dapps attempting to trick users into signing in are prevented from reusing that identity elsewhere, helping to mitigate certain types of phishing attacks.
IC-SIWB / IC-SIWE / IC-SIWS that don’t offer this isolation are susceptible to these traditional web2-style phishing attacks. This is due to the fact that the identity provider canister doesn’t include the request origin in the delegation derivation.
This behavior could be motivated from a UX perspective whereby the user receives the same IC principal across multiple applications and there exists a one-to-one mapping between an IC principal and the corresponding BTC / ETH / SOL address. However, this opens up the user to phishing attacks. In this attack, the attacker uses a seemingly indistinguishable domain (for example, h0nest.com) and tricks the user to sign in for honest.com and extort a successful delegation for the user’s IC principal. With that delegation, the attacker would have access to funds in all the ledgers corresponding to the delegation’s IC principal. Also, if this principal has permissions on any web app (e.g. full account permissions as in II), the attacker gains all of the permissions associated with the principal.
Risk
An honest user can be tricked by a malicious actor (e.g. owning h0nest.com) to sign a login message for honest.com, and on receiving a successful delegation, can steal all the funds owned by the IC principal associated with the BTC / ETH / SOL address.
If the login mechanism is used by a DeFi application, the loss of funds could be very significant.
To make such phishing attacks succeed, the malicious actor could e.g. advertise an airdrop on h0onest.com on social media to trick users to sign in. Not every user might fall for it, but it is likely that some do, as is known from e.g. password phishing attacks in web2.
Risk Analysis
Risk Level: High
-
Likelihood: Likely
An attacker can just create a frontend dapp which clones a popular DeFi website using the SIW* mechanism and phish users and extort funds. -
Impact: Major
This would result in loss of funds held in that IC address and no chance of recovery.
Recommendations
We discuss three approaches to address the issue. However, depending on the application, there may be other solutions as well.
1. Verifying the app origin in the wallet
This recommendation is not possible if your wallet doesn’t verify the origin specified in the message. Please see the second and third recommendations below. See Wallet compatibility matrix to understand which wallets support the verification.
The recommendation is only secure if and only if 1 and 2 are implemented properly.
- Wallets implement the Verifying the Request Origin part of the standard correctly. However, based on our analysis, only Phantom and Metamask seem to support this standard fully for Solana and Ethereum respectively.
- The SIW* IdP canister includes the origin in the delegation derivation. This requires adapting the SIW* IdP canister.
Flow:
- The frontend calls the IdP canister method
siwe_prepare_loginwith payload (Address, frontend origin). It receives a SIWE message from the canister. The SIWE message specifies the domain as the frontend origin. - The frontend initiates the call to the MetaMask wallet to sign the SIWE message. According to the specification, the wallet will verify the domain in the message is the one requesting the signature (frontend origin).
- The frontend calls
siwe_loginwith the signature. - The IdP canister verifies the signature and includes the frontend origin in the principal derivation.
Phishing flow outcome:
If h0nest.com prepares a SIWE message for honest.com and requests a signature from MetaMask, it wouldn’t sign it since the request origin doesn’t match.
From ERC-4361 — Verifying the Request Origin
Wallet implementers MUST prevent phishing attacks by verifying the origin of the request against the scheme and domain fields in the SIWE Message. For example, when processing the SIWE message beginning with “example.com wants you to sign in…”, the wallet checks that the request actually originated from https://example.com.
The origin SHOULD be read from a trusted data source such as the browser window or over WalletConnect (ERC-1328) sessions for comparison against the signing message contents.
Wallet implementers MAY warn instead of rejecting the verification if the origin is pointing to localhost.
SIWS specification (message verification snippet)
In Message verification,
// verify if parsed domain is same as the expected domain
if (data.domain !== expectedURL.host) {
errors.push(VerificationErrorType.DOMAIN_MISMATCH);
}
// verify if parsed uri is same as the expected uri
if (data.uri && data.uri.origin !== expectedURL.origin) {
errors.push(VerificationErrorType.URI_MISMATCH);
}
2. Verifying the app origin using a passkey (as a second factor)
This recommendation does not hold if the dapps holds the funds directly in the principal associated with SIW. delegation. Please see recommendation three in this case.
Alternatively, employ passkeys which bind key material to the app origin to make this secure, e.g. using one of these approaches:
- For any token transaction or privileged operation, in addition to using the SIW* principal, require a second step passkey authorization. Recovery (if you lose the passkey) could e.g. be addressed by allowing to transfer all assets to a predefined “rescue” account even with the SIW* delegation only.
- If an entire “session” should be authenticated, create an entirely new principal in the SIW* canister that requires both the wallet signature AND a passkey authorization. However, this poses issues with recovering passkeys which could lead to significant complexity.
3. Get user consent on every transaction (ICRC21 standard)
This recommendation provides a pathway for building flows where the wallet in use does not support the SIW standard, and the funds are directly held by the principal associated with the SIW* delegation.
In this case, we recommend considering the ICRC21 call consent messages standard. Here, the permission level of the SIW* IdP canisters are downgraded—from being able to sign delegations that can perform all transactions, to signing a specific canister call that can be safely displayed and signed by the corresponding wallet. The SIW* canister takes the role of the ICRC21 signer. The rough flow is as follows:
- The frontend (relying party) builds the transaction (e.g., transferring funds from the ledger) and calls the SIW* canister.
- The SIW* canister calls the target canister to fetch a consent message for the transaction via the ICRC-21 standard. The signer bears the responsibility of validating whether the rendered consent message matches the canister call parameters provided by the frontend. If the validation succeeds, the consent message is forwarded to the frontend.
- The frontend prompts the user to sign the ICRC-21 consent message using their wallet. The user is expected to validate the consent message, which details the transaction.
- The frontend submits the bundle to the
sign_transaction_with_x(“sign-transaction with X”) method of the SIW* canister. - If the signature of the consent message is valid, the SIW* canister signs the transaction and returns it to the frontend.
- The frontend submits the signed transaction, completing it successfully.
While phishing is still possible, the advantages of using ICRC21 in this setting are:
- A phishing attempt, rather than getting a delegation that can control all the funds associated with the principal, can only aim at signing individual transactions. While this can still be risky, it limits the scope of a potential attack.
- The wallet is used to sign individual transactions that contain explicit, human readable consent messages about transactions. It would hopefully be more likely (compared to signing delegations) that a victim verifies and spots a malicious transaction and rejects it.
Wallet Compatibility Matrix
| Wallet | Ecosystem | Does it support SIW standard? | Displays domain / URI | Performs domain check | Risk of phishing |
|---|---|---|---|---|---|
| Coinbase Wallet | Bitcoin | Not supported | Not supported | Not supported | Not valid |
| Unisat | Bitcoin | No | Yes | No | Medium |
| Bitget | Bitcoin | No | Yes | No | Medium |
| Xverse | Bitcoin | No | No | No | High |
| Phantom | Bitcoin | No | Yes | No | Medium |
| Okx | Bitcoin | No | Yes | No | Medium |
| Phantom | Solana | Yes | Yes | Yes | Low |
| Coinbase Wallet | Solana | No | Yes | No | Medium |
| Solflare | Solana | No | Yes | No | Medium |
| Trust Wallet | Solana | No | Yes | No | Medium |
| Metamask | Ethereum | Yes | Yes | Yes | Low |
| Phantom | Ethereum | No | Yes | No | Medium |
| Coinbase Wallet | Ethereum | No | Yes | No | Medium |
| Bitget | Ethereum | No | Yes | No | Medium |
Relevant Links
- https://github.com/AstroxNetwork/ic-siwb
- https://github.com/kristoferlund/ic-siwe
- https://github.com/kristoferlund/ic-siws
- https://github.com/AstroxNetwork/ic-siwb/security/advisories/GHSA-xqx6-6wr2-m9pc
- https://eips.ethereum.org/EIPS/eip-4361
- https://github.com/ChainAgnostic/CAIPs/pull/122
- https://github.com/phantom/sign-in-with-solana
- https://github.com/dfinity/wg-identity-authentication/blob/main/topics/ICRC-21/icrc_21_consent_msg.md