Is Keeper Wallet safe?
We analyzed Keeper Wallet version 2.13.10's actual code and gave it a 55/100 trust score. Keeper Wallet fits its stated purpose but combines broad webpage…
Bottom line
Keeper Wallet fits its stated purpose but combines broad webpage reach, high-impact wallet actions, a permission-boundary flaw, and persistent analytics.
What it can access
It runs across all HTTP(S) pages and exposes wallet signing and cryptographic functions, which fit a web wallet but create broad, high-impact access.[Q1][Q2][Q5][Q16]
Security weaknesses
A different scheme or port using an approved hostname may inherit wallet authorization, increasing phishing and unwanted cryptographic-operation risk.[Q16][Q21]
Signs of misuse
It persistently sends site hostnames, wallet activity, device context, and a random user reference to analytics services.[Q6][Q12][Q13]
Code findings
What access does this extension ask for, and does that access make sense for what it claims to do?
It requests access to every HTTP and HTTPS page, all frames, tabs, local and unlimited storage, alarms, idle state, and clipboard writing. Those capabilities support a web wallet, but the all-page wallet bridge and custody of signing keys create inherently high impact.
Runs contentscript.js on all HTTP(S) frames and requests alarms, clipboardWrite, idle, storage, unlimitedStorage, and tabs. — manifest.json:content_scripts,permissions
Exposes authentication, signing, publishing, shared-key, encryption, and decryption methods to pages. — extracted/inpage/src/inpage.ts:92-111
Encrypts custodial wallet data under the user's password and restores it only after decryption. — extracted/background/src/controllers/wallet.ts:29-46,159-184
Which websites can it run on, and can it read or change what appears on those pages?
The wallet bridge runs in every HTTP and HTTPS frame. It does not scrape or rewrite ordinary page content, but any matching page can call the exposed KeeperWallet services and ask the extension to perform wallet operations subject to its permission and approval flow.
Matches http://*/* and https://*/* with all_frames enabled. — manifest.json:content_scripts
Injects inpage.js and relays the page MessagePort to a long-lived extension runtime port. — extracted/contentscript/src/contentscript.ts:6-53
Creates the page-visible KeeperWallet API and public-state subscription. — extracted/inpage/src/inpage.ts:92-131
Can it see sensitive information you type, such as passwords, payment details, messages, or form entries?
No evidence of this behavior was found in the reviewed package.
Its complete behavior is injecting the packaged API and forwarding MessagePort data. — extracted/contentscript/src/contentscript.ts:6-53
Publishes fixed wallet methods rather than form or DOM readers. — extracted/inpage/src/inpage.ts:92-131
Can it access private browser data such as cookies, signed-in sessions, browsing history, bookmarks, or downloads?
No evidence of this behavior was found in the reviewed package.
Permissions: alarms, clipboardWrite, idle, storage, unlimitedStorage, tabs — no cookies/history/bookmarks/downloads — manifest.json:12-16
tabs API used for extension-owned popup/notification window management only — background.js:2
Can it access anything else on your device, such as files, location, camera, microphone, clipboard, or installed applications?
It can write wallet data to the clipboard and stores an encrypted vault in extension storage. The account UI can reveal and copy a seed or private key only after the user supplies the wallet password; it does not request clipboard reading, files, camera, microphone, or location.
Requests clipboardWrite, storage, and unlimitedStorage but not clipboardRead or device sensors. — manifest.json:permissions
Seed, encoded seed, and private-key getters first validate the supplied vault password. — extracted/background/src/controllers/wallet.ts:378-403
Persists private wallet data as a password-encrypted vault. — extracted/background/src/controllers/wallet.ts:29-46,159-168
Does it send information outside your browser? If so, what information is sent, where does it go, and why?
It sends functional wallet data to configured blockchain nodes, matchers, identity services, metadata services, and transaction publishers.
Creates and persists a nanoid user ID and builds analytics events with browser, OS, language, network, site origin, and wallet-event properties. — extracted/background/src/controllers/statistics.ts:111-140,217-283
Posts queued events to Amplitude and Mixpanel, with Mixpanel explicitly configured to derive the user's IP. — extracted/background/src/controllers/statistics.ts:153-215
Tracks approved transaction type/dApp and allowed or disabled origin domains. — extracted/background/src/background.ts:528-568,629-676
Sends expected balance, matcher, order, and transaction traffic to configured blockchain services. — extracted/background/src/controllers/network.ts:110-220
Does it download or run code, settings, or instructions supplied by a remote server?
It repeatedly downloads remote wallet configuration, including identity-service services, NFT URLs, asset limits, and error-reporting filters. Those values alter network destinations and feature behavior but are not executed as JavaScript; executable code remains packaged and the CSP restricts scripts to the extension itself.
Fetches main.json from the Keeper-Wallet GitHub repository and applies asset, NFT, and error-reporting settings. — extracted/background/src/controllers/remoteConfig.ts:152-172
Fetches Waves network configuration and then identity configuration from server-provided config-service URLs. — extracted/background/src/controllers/remoteConfig.ts:175-230
Uses the resulting identity configuration for authentication, bearer-token API calls, and co-signing requests. — extracted/background/src/controllers/IdentityController.ts:281-330,415-424,581-597
Limits extension-page scripts to self and bundled WebAssembly support; no remote JavaScript source is allowed. — manifest.json:content_security_policy
Can it take actions without a clear user request, such as opening pages, redirecting searches, downloading files, or sending requests?
Without a user click, it refreshes main and identity configuration roughly every minute, checks balances and asset metadata on alarms, drains analytics queues, reports errors, and can lock the wallet after inactivity. These are background wallet functions, not hidden downloads or redirects, but they generate recurring remote traffic.
Fetches and reschedules both configuration updates with one-minute delays. — extracted/background/src/controllers/remoteConfig.ts:68-80,152-230
Schedules activity tracking and delayed analytics uploads. — extracted/background/src/controllers/statistics.ts:124-150
Registers periodic metadata, suspicious-asset, and swappable-asset refresh alarms. — extracted/background/src/controllers/assetInfo.ts:128-162
Can it change important browser settings, including your proxy, search engine, homepage, privacy settings, or other extensions?
No evidence of this behavior was found in the reviewed package.
Is any important behavior difficult to inspect because the code is hidden, heavily obfuscated, dynamically generated, or supplied by third parties?
The installed runtime uses large minified bundles and bundled dependencies, which makes casual inspection difficult. First-party source maps recover readable TypeScript for the important trust boundaries, so the core page bridge, permissions, vault, telemetry, and configuration paths remain auditable.
The installed service-worker bundle is approximately 786 KB and minified. — background.js:bundle
Includes first-party source content for the core background controllers and trust-boundary code. — background.js.map:sourcesContent
Includes readable first-party UI and approval-flow sources alongside bundled dependencies. — popup.js.map:sourcesContent
Does it use eval(), new Function(), or string-based timers to turn text into executable code?
No evidence of this behavior was found in the reviewed package.
Allows self-hosted scripts and packaged WebAssembly compilation, not traditional eval. — manifest.json:content_security_policy
The retry timer receives the fixed sendPing function. — extracted/background/src/ipc/ipc.ts:145-163
The approximately 50 KB WebAssembly module is packaged locally with the wallet's cryptographic runtime. — assets/bae819e1c8f2e09cc86e.wasm:binary
Does it track the websites, pages, searches, or links you visit?
It does not report every page visit, but it persistently records approved site hostnames and sends a hostname to analytics when the user allows or disables wallet access and when a request is approved. Transaction analytics can also include the invoked dApp address.
Stores per-host wallet permissions in local extension storage. — extracted/background/src/controllers/permissions.ts:69-147
Adds origin hostnames and dApp identifiers to approval and permission analytics events. — extracted/background/src/background.ts:528-568,629-647
Uploads those event properties with the persistent analytics identity. — extracted/background/src/controllers/statistics.ts:217-260
Does it create a persistent ID or browser fingerprint to recognize you?
It generates a persistent random user ID, saves it in local extension storage, and uses it as the Amplitude user ID, Mixpanel user/distinct ID, and Sentry user ID. Analytics also include browser, OS, language, network, and IP-derived context.
Loads an existing userId or generates one with nanoid, persists it, and gives it to Sentry. — extracted/background/src/controllers/statistics.ts:111-120
Places the same ID and device context in Amplitude and Mixpanel events. — extracted/background/src/controllers/statistics.ts:217-260
Defines userId as persistent local state and writes controller updates to chrome.storage.local. — extracted/background/src/storage/storage.ts:73-94,151-183
Does it send cookies, session details, authentication data, or page contents elsewhere?
Expected wallet functions send public wallet addresses, transaction or order data, signed data, and identity bearer tokens to configured blockchain and identity services. Analytics additionally receive approved site hostnames and transaction activity.
Sends identity bearer tokens and signing payloads to the configured identity API. — extracted/background/src/controllers/IdentityController.ts:415-424,581-597
Queries matcher and node APIs and broadcasts wallet operations to configured services. — extracted/background/src/controllers/network.ts:110-220
Uploads wallet event metadata and site/dApp identifiers to analytics. — extracted/background/src/controllers/statistics.ts:217-260
Keeps private wallet material inside the locally encrypted vault; no upload call is present. — extracted/background/src/controllers/wallet.ts:29-46,159-184
Does it record typing, form entries, clipboard contents, or screenshots?
No evidence of this behavior was found in the reviewed package.
Declares clipboardWrite but not clipboardRead or capture permissions. — manifest.json:permissions
Contains no keyboard, input, form, or screenshot handling. — extracted/contentscript/src/contentscript.ts:6-53
Secret retrieval APIs validate the wallet password before returning data to the extension UI. — extracted/background/src/controllers/wallet.ts:378-403
Can a website or remote server send commands that make the extension take actions?
Any HTTP(S) page can call the injected wallet services. First use normally requires origin approval and most signing requests require a second confirmation; optional auto-sign can remove that second prompt within user-configured limits.
Takes sender.url from the Chrome port but reduces it to new URL(sender.url).hostname before creating the page API. — extracted/background/src/background.ts:1317-1331
Uses that hostname as the stored permission key and otherwise opens origin-approval UI. — extracted/background/src/background.ts:745-813
Transaction methods show approval UI unless user-configured auto-sign accepts the amount and interval. — extracted/background/src/background.ts:961-1038
Shared-key, encryption, and decryption methods require host approval but no separate per-call confirmation. — extracted/background/src/background.ts:1169-1243
Does it alter links, referral codes, advertisements, shopping carts, or search results?
No evidence of this behavior was found in the reviewed package.
Content script only injects inpage.js and relays API messages; no DOM mutation, link rewriting, or ad injection observed. — contentscript.js:1
Does it redirect or modify web traffic, request headers, downloads, or proxy settings?
No evidence of this behavior was found in the reviewed package.
Permissions list (alarms, clipboardWrite, idle, storage, unlimitedStorage, tabs) contains no traffic-interception or proxy capabilities. — manifest.json:12-16
Can it communicate with software on the computer or services running on localhost?
No evidence of this behavior was found in the reviewed package.
Network endpoints are remote Waves nodes, matchers, api.keeper-wallet.app, and IPFS; no 127.0.0.1 or localhost URLs observed. — background.js:2
No native_messaging or external_connectable declarations present. — manifest.json:1-30
Does it decode, decrypt, or unpack hidden data and then execute or inject it?
No evidence of this behavior was found in the reviewed package.
Decrypts the local vault into structured wallet records after password validation. — extracted/background/src/controllers/wallet.ts:29-46,170-184
Executable scripts are restricted to packaged self content; only packaged WebAssembly compilation is additionally allowed. — manifest.json:content_security_policy
Can ordinary websites access privileged extension features through messaging or exposed files?
Every ordinary HTTP(S) page receives access to the KeeperWallet request bridge. The bridge intentionally reaches privileged wallet functions, with origin and action approval controls.
Runs the relay in every HTTP(S) frame and makes inpage.js available on every URL. — manifest.json:content_scripts,web_accessible_resources
Transfers a MessagePort to the page and forwards its requests to chrome.runtime.connect. — extracted/contentscript/src/contentscript.ts:6-53
Exposes the fixed wallet API to page JavaScript. — extracted/inpage/src/inpage.ts:92-131
Authenticates the page connection by hostname only before routing it to privileged handlers. — extracted/background/src/background.ts:1317-1331
Does suspicious behavior activate only for certain users, websites, dates, or remote settings?
No evidence of this behavior was found in the reviewed package.
Applies remotely fetched assets, NFT, and error-reporting configuration. — extracted/background/src/controllers/remoteConfig.ts:152-172
Builds identity configuration from remotely supplied Waves configuration-service URLs. — extracted/background/src/controllers/remoteConfig.ts:175-230
Uses downloaded Cognito and API destinations for login, authenticated user lookup, and identity signing. — extracted/background/src/controllers/IdentityController.ts:281-330,415-424,581-597
Does it perform hidden resource-intensive work, such as cryptocurrency mining?
No evidence of this behavior was found in the reviewed package.
Three named alarms (updateSuspiciousAssets, updateInfo, updateSwappableAssetIdsByVendor) perform lightweight metadata fetches; no compute-intensive loops observed. — background.js:2
Does it change form fields or where a form sends its information?
No evidence of this behavior was found in the reviewed package.
Complete page interaction is limited to injecting inpage.js and relaying MessagePort traffic. — extracted/contentscript/src/contentscript.ts:6-53
Defines wallet API globals without reading or changing forms. — extracted/inpage/src/inpage.ts:92-147