Is IOTA Wallet safe?

Medium risk

IOTA Wallet sends detailed financial activity events — transactions, DApp connections, and key exports — to Amplitude's analytics servers.

When users perform wallet actions such as sending coins, approving transactions, connecting to DApps, or exporting account keys, the extension captures those events along with associated metadata and transmits them via HTTPS to Amplitude's EU-region endpoint. The Amplitude SDK is initialized with a hardcoded API key and also uses navigator.sendBeacon to flush data on page hide and visibility-change events. No confirmed claims establish data collection beyond what the Amplitude integration describes.

tooling-adminv1.12.1Chrome Web Store
45Risk
Who publishes it

IOTA Ecosystem DLT Foundation - no other listings under this identity

What this publisher told the store about itself, and the other listings that told it the same thing.

Publisher
tooling-admin
Declared legal entity
IOTA Ecosystem DLT Foundation
Registered contact
IOTA Ecosystem DLT Foundation

AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.

Publishers can request a review.

Findings

IOTA Wallet sends wallet-action analytics to Amplitude

MediumunwantedCWE-359Dynamic sandbox

Using select IOTA Wallet features records analytics for sending coins, connecting a DApp, or opening export-keys.

What actually happens

You did this

You perform a tracked wallet action inside IOTA Wallet.

Examples in the shipped code include sending coins, connecting a DApp, responding to a transaction request, and choosing Export Account Keys.

The extension did this

The extension creates an analytics event for that action and sends it to Amplitude.

Dynamic analysis observed a POST to Amplitude after wallet activity, and the source contains the matching event names and properties.

Captured request

POSThttps://api.eu.amplitude.com/2/httpapi

Dynamic analysis observed the request after wallet activity; the evidence notes a body containing the hardcoded API key, a device ID, and an Amplitude page-location field.

Concrete fields shown by the code and observed traffic

  • Analytics project key
    2a5d35822a1bab41835813f0223f319e

    Tells Amplitude which analytics project receives the event from your extension.

  • Your analytics device ID
    d4f2c6b8-9a01-4f32-9d7c-0d1e2f3a4b5c (illustrative)

    Lets the analytics service group multiple wallet events from the same browser profile.

  • Your page location
    chrome-extension://iidjkmdceolghepehaaddojmnjnkkija/ui.html (illustrative)

    Shows the extension page context associated with the wallet event.

  • Your wallet action
    sent coins

    Records which wallet feature you used, such as sending coins or starting a DApp connection.

  • Your action details
    coinType: IOTA; amount: 1.25; applicationUrl: https://app.example.iota.org (illustrative)

    Adds action-specific details, such as the coin type and amount for a send or the application URL for a DApp request.

  • Your approval result
    approvedTransaction: true; receivedFailureWarning: false

    Shows whether you approved a transaction request and whether the approval followed a warning prompt.

  • Your account type
    Private Key

    When you open the export-account-keys flow, the analytics event records the account type selected in the wallet.

The code that does this

The shipped extension initializes Amplitude and maps wallet actions to analytics events

Readable version

Amplitude API key and EU server-zone configuration

background.js
let sa = {        iotawallet: "2a5d35822a1bab41835813f0223f319e"      },      su = {        plan: {          version: "3",          branch: "main",          source: "web",          versionId: "41c28342-e260-4c3e-8465-6618203f115a"        },        ...{          ingestionMetadata: {            sourceName: "browser-typescript-ampli",            sourceVersion: "2.0.0"          }        },        serverZone: tu.EU      };

EU endpoint selector used by the bundled Amplitude SDK

ui.js
nQ=function(t,n,i){if(void 0===t&&(t=""),void 0===n&&(n=nX().serverZone),void 0===i&&(i=nX().useBatch),t)return{serverUrl:t,serverZone:void 0};var a,o=["US","EU"].includes(n)?n:nX().serverZone;return{serverZone:o,serverUrl:(a=i,"EU"===o?a?"https://api.eu.amplitude.com/batch":"https://api.eu.amplitude.com/2/httpapi":a?"https://api2.amplitude.com/batch":nj)}}

Amplitude load function and beacon flush handlers

ui.js
async function le(){var t;let n,i,a;s8.load({environment:"iotawallet",disabled:!1,client:{configuration:{optOut:!1,identityStorage:"cookie",autocapture:{attribution:!1,fileDownloads:!1,formInteractions:!1,pageViews:!0,sessions:!0,elementInteractions:!1,frustrationInteractions:!1,networkTracking:!1,webVitals:!1,pageUrlEnrichment:!0},logLevel:mB.None,flushIntervalMillis:1e3,flushQueueSize:5}}}),s8.client.add((t=s8.client,n=null,i=null,{name:"dialog-context",type:"enrichment",setup:async()=>(n="u"<typeof window||"u"<typeof document?()=>{}:(document.addEventListener("click",rK,!0),()=>{document.removeEventListener("click",rK,!0)}),i=function(t){if("u"<typeof window||"u"<typeof document)return()=>{};let n=new MutationObserver(n=>{for(let i of n)i.addedNodes.forEach(n=>{if(n instanceof HTMLElement){var i,a;((null==(i=n.matches)?void 0:i.call(n,rH))?n:null==(a=n.querySelector)?void 0:a.call(n,rH))&&setTimeout(()=>{let n=r$();t.track("Dialog Opened",{dialog_title:n})},50)}})});return n.observe(document.body,{childList:!0,subtree:!0}),()=>{n.disconnect()}}(t),Promise.resolve()),execute:async t=>{if("u"<typeof window||"u"<typeof document)return t;let n=rU.get(),i=(null==n?void 0:n.dialogTitle)??r$();return i?{...t,event_properties:{...t.event_properties,dialog_title:i}}:t},teardown:async()=>(n&&n(),i&&i(),rU.clear(),Promise.resolve())})),window.addEventListener("pagehide",()=>{s8.client.setTransport("beacon"),s8.flush()}),document.addEventListener("visibilitychange",()=>{"hidden"===document.visibilityState&&(s8.client.setTransport("beacon"),s8.flush())}),s8.client.add((a="dev_",{name:"environment-plugin",type:"enrichment",setup:async()=>{},execute:async t=>{let n=t.event_type;return t}}))}

Event classes for the wallet actions named in the claim

ui.js
class sF{event_properties;event_type="exported account keys";constructor(t){this.event_properties=t,this.event_properties=t}}class sq{event_properties;event_type="opened application";constructor(t){this.event_properties=t,this.event_properties=t}}class sU{event_properties;event_type="opened link";constructor(t){this.event_properties=t,this.event_properties=t}}class sV{event_properties;event_type="opened transaction";constructor(t){this.event_properties=t,this.event_properties=t}}class sH{event_properties;event_type="pinned coin";constructor(t){this.event_properties=t,this.event_properties=t}}class s${event_type="renamed account"}class sK{event_type="reset wallet"}class sG{event_properties;event_type="responded to connection request";constructor(t){this.event_properties=t,this.event_properties=t}}class sW{event_properties;event_type="responded to transaction request";constructor(t){this.event_properties=t,this.event_properties=t}}class sY{event_properties;event_type="selected coin";constructor(t){this.event_properties=t,this.event_properties=t}}class sJ{event_properties;event_type="selected validator";constructor(t){this.event_properties=t,this.event_properties=t}}class sX{event_properties;event_type="sent coins";constructor(t){this.event_properties=t,this.event_properties=t}}class sZ{event_properties;event_type="sent collectible";constructor(t){this.event_properties=t,this.event_properties=t}}class sQ{event_properties;event_type="staked IOTA";constructor(t){this.event_properties=t,this.event_properties=t}}class s0{event_properties;event_type="started dapp connection";constructor(t){this.event_properties=t,this.event_properties=t}}

Wallet-action call sites and concrete event properties

ui.js
onClick:function(){let n=null==t?void 0:t.type;n&&s8.exportedAccountKeys({accountType:qJ[n]}),m(`/accounts/export/${t.id}`)}(0,dg.useEffect)(()=>{if(s){let t=lo(s.name,s.origin);s8.startedDappConnection({applicationName:t,applicationUrl:s.origin})}},[s])onSuccess:t=>(f.invalidateQueries({queryKey:["get-coins"]}),f.invalidateQueries({queryKey:["coin-balance"]}),s8.sentCoins({coinType:g,amount:Number(x.values.amount)}),u(`/receipt?txdigest=${encodeURIComponent(t.digest)}&from=transactions`))onSubmit:async n=>{if(!p){if(n&&v)return void d(!0);await l(Cy({approved:n,txRequestID:t.id,signer:s})),eiw.includes(t.origin)||s8.respondedToTransactionRequest({applicationUrl:t.origin,approvedTransaction:n,receivedFailureWarning:!1})}}onResponse:async n=>{await l(Cy({approved:n,txRequestID:t.id,signer:s})),s8.respondedToTransactionRequest({applicationUrl:t.origin,approvedTransaction:n,receivedFailureWarning:!0}),d(!1)}

External analytics destination

    • api.eu.amplitude.com

    Amplitude EU analytics ingestion receives the wallet-action events over HTTPS.

When this fires

When a batch threshold is hit · flushes at 5 queued events

The extension is configured to flush analytics quickly after activity, with a one-second flush interval and a queue size of five events.

Where it sends data

Destinations our analysis observed IOTA Wallet contacting. Sending data somewhere is not a finding on its own - an extension that syncs your settings has to talk to its own server - but it is where your data can go, and who else it goes to.

  • api.eu.amplitude.com

    IOTA Wallet sends data to api.eu.amplitude.com. 8 other extensions we have analyzed send data here.

Updated 30 September 2026iidjkmdceolghepehaaddojmnjnkkija