Is Fast Wallet safe?
Fast Wallet sends biometric auth keys and a persistent device identifier to api.suiet.app, a third-party server, during biometric setup.
When a user enables, rotates, or disables biometric authentication, the extension transmits a persistent per-device client_id along with public keys and signatures to api.suiet.app — a server operated by Suiet, a separate wallet project. The extension also injects a crypto wallet API (window.fastset) into every webpage the user visits, exposing account access methods such as connect(), signMessage(), and transfer() to all page scripts. Additionally, wallet account addresses and public keys are broadcast via postMessage with a wildcard origin ('*'), making them readable by any frame on the page.
Who publishes itFast - no other listings under this identity, 3 shared hostnames
Fast - no other listings under this identity, 3 shared hostnames
What this publisher told the store about itself, and the other listings that told it the same thing.
Shared hosts - 3 hostnames
Hostnames hardcoded in this extension that few other listings call. That can mean one operator behind both, and it can equally mean a small shared vendor, so it is context rather than a conclusion. Hosts that many listings call are left out: they are services, not connections.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Biometric auth posts device key data to api.suiet.app
Touch ID setup, rotation, or disable posts biometric-auth records to api.suiet.app with a persistent chrome-prefixed client ID.
Setup/rotation also send public-key material and an auth key.
Source-code evidence; DA captured no request.
- Severity
- Medium unwanted
- Type
- Unexpected
- CWE
- CWE-200
- Source
- Dynamic sandbox
You change or use the wallet's Touch ID authentication flow.
The source paths cover setup, auth-key rotation during biometric unlock, and disable.
The extension prepares a POST to api.suiet.app with the device client ID.
Setup and rotation also include public-key material and a generated auth key.
- Device client IDchrome-q4k8x7m2n5p9r3t6v1s0
Lets the remote auth service tie biometric-auth requests to the same browser profile over time.
- Generated auth keyv7ny8t2q0k5abc9m4x1r6zps
Part of the wallet's Touch ID unlock flow is sent to the remote auth service during setup and rotation.
- Biometric public keypQECAyYgASFYILhO5yVf2j7fX8qfU8G0QnPGk0kQAcW6mXWgpjOjoH0VIlggx9K2m5Wl1jM8TnZP6Qf4GkK7a0F3rB9pV2sH6cD1eA4=
Connects the browser profile to the public-key credential created for Touch ID.
- Signed challengeeyJtZXNzYWdlIjoiRmFzdCBXYWxsZXQiLCJkYXRldGltZSI6IjIwMjYtMDctMTJUMjI6NTA6MzUuNDk0WiIsIm5vbmNlIjo2ODQyMTkzN30=
Shows a Touch ID unlock attempt and links that attempt back to the same device client ID.
The source code issues this POST during Touch ID setup and token-change handling; no request body was recorded during dynamic analysis.
- content-type
- application/json
The source code issues this POST during biometric unlock key rotation; no request body was recorded during dynamic analysis.
- content-type
- application/json
The source code issues this POST when Touch ID is disabled; no request body was recorded during dynamic analysis.
- content-type
- application/json
Biometric-auth code paths in the shipped bundle
Persistent chrome- client ID
assets/auth-DxF_k_Sy.jsasync getClientId() { const meta = await this.storage.loadMeta(); if (!meta) { throw new MetadataMissingError(); } if (!meta.clientId) { meta.clientId = generateClientId(20, void 0, "chrome-"); await this.storage.saveMeta(meta); } return meta.clientId;}Touch ID setup POST
assets/auth-DxF_k_Sy.jsasync biometricAuthEnable({ credentialIdBase64, publicKeyBase64}) { const meta = await this.storage.loadMeta(); if (!meta) { throw new MetadataMissingError(); } const token = this.getToken(); const clientId = await this.getClientId(); const authKey = generateClientId(24); const encryptedToken = encryptString(bufferExports.Buffer.from(authKey), token); try { const resp = await fetch( `https://api.suiet.app/extension/auth/set-auth-key`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ client_id: clientId, auth_key: authKey, public_key_base64: publicKeyBase64 }) } ); if (resp.ok) { meta.biometricData = { credentialIdBase64, publicKeyBase64, encryptedToken }; await this.storage.saveMeta(meta); return true; } } catch (e) { } return false;}Touch ID key rotation POST
assets/auth-DxF_k_Sy.jsasync biometricAuthRotateAuthKey({ challengeBase64, signatureBase64}) { const meta = await this.storage.loadMeta(); if (!meta) { throw new MetadataMissingError(); } if (!meta.biometricData) { throw new Error("Biometric authentication not enabled"); } const clientId = await this.getClientId(); const newAuthKey = generateClientId(24); let shouldClear = false; try { const resp = await fetch( `https://api.suiet.app/extension/auth/rotate-auth-key`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ client_id: clientId, message_base64: challengeBase64, signature_base64: signatureBase64, public_key_base64: meta.biometricData.publicKeyBase64, auth_key: newAuthKey }) } ); if (resp.ok) { const { auth_key: authKey } = await resp.json(); if (authKey) { try { await this.biometricAuthUnlockWithAuthKey(authKey, newAuthKey); return true; } catch (e) { shouldClear = true; } } } else { try { const { error_code: errorCode } = await resp.json(); if (errorCode === "NOT_FOUND") { shouldClear = true; } } catch (e) { } } } catch (e) { } try { if (shouldClear) { delete meta.biometricData; await this.storage.clearMeta(); await this.storage.saveMeta(meta); } } catch (e) { } return false;}Touch ID disable POST
assets/auth-DxF_k_Sy.jsasync biometricAuthDisable() { const meta = await this.storage.loadMeta(); if (!meta) { throw new MetadataMissingError(); } if (meta.biometricData) { delete meta.biometricData; await this.storage.clearMeta(); await this.storage.saveMeta(meta); await fetch(`https://api.suiet.app/extension/auth/delete-auth-key`, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ client_id: await this.getClientId() }) }); }}- api.suiet.app
Receives extension auth POSTs for Touch ID setup, auth-key rotation, token-change handling, and disable requests.
Where it sends data
Destinations our analysis observed Fast 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.suiet.app
Fast Wallet sends data to api.suiet.app. No other extension we have analysed sends data here.