Is QSafe wallet safe?
QSafe wallet sends a SHA-256 hash of the wallet mnemonic to QSafe's daily-login endpoint after unlock.
When a user successfully unlocks the wallet popup, the extension derives the wallet mnemonic, hashes it with SHA-256, and posts the resulting 64-character hex userId to QSafe's backend. This occurs as part of the daily-login request after a correct unlock, not only during wallet creation or import.
Who publishes itQuranium Association - no other listings under this identity
Quranium Association - no other listings under this identity
What this publisher told the store about itself, and the other listings that told it the same thing.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Wallet unlock posts mnemonic hash to QSafe
After a successful QSafe wallet unlock, the popup reads the wallet mnemonic, derives a SHA-256 hash from it, and posts that hash to QSafe's daily-login endpoint as userId, sent to backend-extension.qsafewallet.com as JSON.
- Severity
- High unwanted
- Type
- Unexpected
- CWE
- CWE-359
- Source
- Dynamic sandbox
You unlock the QSafe wallet with the correct password.
The extension reads the wallet recovery phrase, hashes it, and posts the derived value to QSafe.
- Recovery phrase hashc557eec878dfd852ba3f88087c4f350f09c55537ab5e549c3cd14320ec3cef38 (illustrative SHA-256 value)
This is a stable value derived from your wallet recovery phrase, so it can identify the same wallet unlocks over time.
- Content-Type
- application/json
Unlock handler, mnemonic hashing, and daily-login POST
Readable equivalent of the same popup code
assets/main-ItruZbVg.jsconst postDailyLogin = async (mnemonicHash) => { try { const response = await fetch("https://backend-extension.qsafewallet.com/api/v1/login/daily-login", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ userId: mnemonicHash }) }); if (!response.ok) { console.error("Failed to track daily login"); } } catch (error) { console.error("Error tracking daily login:", error); }};const sha256Hex = (mnemonic) => cryptoBrowserifyExports .createHash("sha256") .update(mnemonic) .digest("hex");const unlockAction = async () => { if ( console.log("unlockAction"), ae.value = true, (await sendToBackgroundFromAction({ message: JSON.stringify({ method: InternalMethods.unlock, params: [c.value.trim(), true] }) })).error ) { ee.value = true; ae.value = false; trackGenericEvents(GenericEvents.login_error); return; } try { const keyring = new KeyRingBase(); await keyring.unlock(c.value.trim()); const mnemonic = await keyring.getMnemonic(c.value.trim()); const mnemonicHash = sha256Hex(mnemonic); localStorage.setItem("sessionToken", createSession(keyring)); ee.value = false; c.value = ""; u("update:init"); setTimeout(() => ae.value = false, 750); trackGenericEvents(GenericEvents.login_success); postDailyLogin(mnemonicHash).catch((error) => console.error("Failed to track daily login:", error)); } catch (error) { ee.value = true; ae.value = false; console.error("Keyring unlock failed", error); trackGenericEvents(GenericEvents.login_error); }};- backend-extension.qsafewallet.com
Receives the daily-login POST containing the SHA-256 mnemonic-derived userId value.
Where it sends data
Destinations our analysis observed QSafe 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.
- backend-extension.qsafewallet.com
QSafe wallet sends data to backend-extension.qsafewallet.com. No other extension we have analysed sends data here.