VeilSwap
← All posts
Security2026-10-288 min read

Browser Extension Wallets: Permissions and Silent Updates

We pulled the live builds of six wallet extensions and read their manifests: all six can read every site you visit, and updates arrive without a confirmation box. What that means for a swap.

Every wallet extension you install asks for the right to read and change your data on all websites. That is not a dark pattern; it is the mechanism. An extension has to inject its provider object into every page so that a site's swap button can find it. The side effect is that one piece of software ends up holding both capabilities that matter: it can read the address you paste into a form, and on a site that asks for it, it can sign a transaction. On 2026-10-28 we pulled the current builds of six popular wallet extensions from Google's own update endpoint, unpacked them, and read their manifests. This post is what those files actually declare, why the update channel deserves more suspicion than the permission dialog, and what a swap site like ours can and cannot do about any of it.

What a wallet extension actually is

All six builds are Manifest V3, and that matters because V3 changed the shape of the problem. A V3 wallet is a service worker with no persistent page, one or more content scripts injected at document_start — before the site's own JavaScript runs — and host permissions that decide which origins those scripts may touch. The content script lives in an isolated world, so it cannot read a page's variables directly, but it can read and rewrite the DOM, which is enough to change an address field. Signing is a separate, explicit step: the wallet opens its own window and the user approves. The capability that is easy to forget is the reading one, because it is granted once at install, in a dialog most people dismiss in a second. MetaMask's live manifest, for reference, asks for eleven permissions including cookies, webRequest, identity and offscreen, plus clipboardRead as an optional extra.

The permission sheet we measured on 2026-10-28, 06:02 UTC

The packages we read were MetaMask 13.54.0.0, Phantom 26.35.0, Rabby 0.94.13, Keplr 0.13.53, Trust Wallet 26.42.4 and OKX Wallet 4.21.0. Every one of the six declares access to all http and https origins. MetaMask adds ws, wss, file and localhost:8545, and is the only one that lets any website message it (externally_connectable with a wildcard extension-id list). Rabby uses the blunt all_urls host permission; Keplr injects a content script on all_urls at document_start; Trust Wallet declares clipboardWrite and gcm; OKX pins content scripts on solscan.io, twitter.com and x.com in addition to every site. Packages run 16.4 MB to 54.7 MB, file counts 103 to 1,187, and unpacked JavaScript 15.5 MB to 92.5 MB. That last figure is the honest measure of the attack surface: tens of megabytes of third-party code with standing access to every page you open, updated by someone else.

Silent updates, and what crx_id does and does not protect

A CRX3 package is a small protobuf header followed by a zip. All six had the same shape: two RSA signature proofs, one ECDSA proof, and a signed_header_data field carrying a 16-byte crx_id. Map each hex digit of that id to a letter from a to p and you get the 32-character extension ID shown in the store; we checked, and it reproduces all six exactly. So the key is bound to the ID and nobody else can serve a build for it. The publisher can serve anything at all, and Chrome installs it without asking: the check runs in the background against the same public endpoint we used, the browser version is passed as a parameter, and the new code is live on the next page load. There is no changelog you must acknowledge. That is also why the interesting failures sit one layer down, in dependencies: @solana/web3.js 1.95.6 went up on 2024-12-03 at 15:10:07 UTC and 1.95.7 at 15:20:23, both are gone from the registry version list now, and the clean 1.95.8 arrived at 20:25:40 — five hours and fifteen minutes later. @ledgerhq/connect-kit ran 1.1.5 at 08:49:04, 1.1.6 at 09:44:57, 1.1.7 at 10:37:24 and clean 1.1.8 at 13:18:35 on 2023-12-14, four and a half hours. In neither case was the window days; it was the time automated installs needed to pick the version up.

What a swap needs, and what the extension can still do

This is where our own product shape is relevant. A VeilSwap order takes five fields — from-asset, to-asset, amount, payout address, refund address — and nothing else. No account, no email, no wallet connection, no signature. A grep of our front end for window.ethereum, WalletConnect and wagmi returns nothing, because no part of the flow asks a wallet to do anything. That removes the largest risk class, the approval prompt people click without reading. It does not remove the reading permission: a wallet extension still runs on veilswap.io at document_start and can see the address field. Server-side format and checksum checks run when the order is created, which stops a typo but not a well-formed substitution. Measured quotes at 06:04 UTC, for scale: 100 USDT-TRC20 bought 0.14408925 XMR and 5,000 bought 8.06917242 XMR — 694.01 versus 619.64 USDT per XMR, a 12% gap that is per-order fixed cost, not something a wallet influences. 1 XMR sold for 589.282718 USDT, and 0.05 BTC bought 6.54643747 XMR at 130.92875 XMR per BTC, roughly 77,154 USD per BTC. Catalogue: 520 assets across 73 networks. (recovering misdirected funds)

Six steps, and three things people get wrong

First, keep a browser profile for wallets and do swaps in a profile with no wallet extension at all; addresses move between them by copy-paste, and that is exactly enough. Second, in the extensions page set each wallet's site access to on-click or to a short allowlist if you only use it for one chain, and re-check after every update. Third, before moving real money, compare the installed version against the store listing — the versions above are what was live at 06:02 UTC, not what you happen to have. Fourth, treat any request for a seed phrase as an attack regardless of what the popup claims; no website flow needs it. Fifth, sign with hardware where the amount justifies it, and read the address on the device screen, not in the browser. Sixth, if an update grows the permission list, remove the extension and reinstall deliberately instead of clicking through. The three misjudgements: store review does not prevent a malicious update, because update review is lighter than first submission and the six packages above carry 233, 230, 64, 31, 234 and 392 JavaScript files; incognito is not a sandbox, since extensions run there only when explicitly allowed and then read those pages too; and installing fewer wallets does not scale risk down linearly, because each of them holds the all-site permission independently. (seed backup guide)

The short version: a browser wallet is not a wallet the way a hardware device is — it is a page-reading program that happens to hold keys, and it is replaced silently by whoever controls its publisher key. Swapping does not require it. An order needs an address and an amount; a site that asks you to connect and sign is asking for more than the trade needs. Keep the wallet in one profile, do the swap in another, and check the address character by character in the place you copied it from. That is a smaller ask than trusting 92 MB of code you have never read.

Frequently asked questions

Can a wallet extension be drained, and how does it usually happen?

Yes, and usually not by breaking the cryptography. The loss comes from code running with the wallet's own permissions: a malicious dependency picked up by an automated install (the @solana/web3.js window lasted 5 hours 15 minutes; the Ledger Connect Kit window 4 hours 30 minutes), a lookalike extension, or a page that gets you to approve a signature you did not read. The keys are intact — the permission model is what gets used.

Do I need a wallet extension at all to swap?

No. A VeilSwap order takes five fields — from-asset, to-asset, amount, payout address, refund address — and no signature. You can generate the payout address in a hardware wallet or a phone wallet, type it in, and never install an extension at all. The extension is convenience for dapp signing; this flow does not sign anything.

Does store review stop a malicious update?

No. Review happens per submission, and update review is lighter than first-submission review. The six packages we unpacked carry 233, 230, 64, 31, 234 and 392 JavaScript files, and the installed code changes on the next page load after a background update check. Your realistic control is the permission list and the version number you can see, not the review process.

Ready to swap?

No account · No KYC · No email

Exchange now
Browser Extension Wallets: Permissions and Silent Updates