From 07a8ea5b2476febc3568ecbdaa864cbb6fe60d45 Mon Sep 17 00:00:00 2001 From: alez04 Date: Tue, 2 Jun 2026 17:07:49 +0300 Subject: [PATCH 1/4] fix: clear sensitive state immediately on wallet lock --- src/components/dapp/dapp-approval-drawer.tsx | 6 +++++- src/pages/manage-accounts.tsx | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/components/dapp/dapp-approval-drawer.tsx b/src/components/dapp/dapp-approval-drawer.tsx index 9b6b816..c4c697c 100644 --- a/src/components/dapp/dapp-approval-drawer.tsx +++ b/src/components/dapp/dapp-approval-drawer.tsx @@ -35,6 +35,7 @@ import { import AddressLabel from '@/components/address-label' import { useTxTypeDescription } from '@/hooks/use-tx-type-description' import { isWalletLocked } from '@/lib/lock' +import IdnWarningBadge from '@/components/idn-warning-badge' import { validateVaultPassphrase } from '@/lib/vault' import { toast } from 'sonner' @@ -72,7 +73,9 @@ const DappApprovalDrawer = () => { useEffect(() => { const syncLockState = () => { - setLocked(isWalletLocked()) + const nowLocked = isWalletLocked() + if (nowLocked) setPassphrase('') + setLocked(nowLocked) } syncLockState() @@ -286,6 +289,7 @@ const DappApprovalDrawer = () => { {t('dapp.approval.origin')}

{current.origin}

+ {current.method === 'connect' && connectSummary && (
diff --git a/src/pages/manage-accounts.tsx b/src/pages/manage-accounts.tsx index 823c6ba..2ed267b 100644 --- a/src/pages/manage-accounts.tsx +++ b/src/pages/manage-accounts.tsx @@ -22,6 +22,7 @@ import { repairDuplicateVaultEntries, setOnboarded, } from '@/lib/vault' +import { isWalletLocked } from '@/lib/lock' import AccountListItem from '@/components/pages/manage-accounts/account-list-item' import AddAccountDrawer from '@/components/pages/manage-accounts/add-account-drawer' import RenameAccountDrawer from '@/components/pages/manage-accounts/rename-account-drawer' @@ -126,6 +127,19 @@ const ManageAccounts = () => { } }, [refreshFromCache]) + useEffect(() => { + const onLock = () => { + if (!isWalletLocked()) return + setRevealedSeed('') + setSeedTarget(null) + setPassphraseInput('') + setPassphrasePromptOpen(false) + setPendingAction(null) + } + window.addEventListener('wallet-lock-updated', onLock) + return () => window.removeEventListener('wallet-lock-updated', onLock) + }, []) + const balanceQueries = useQueries({ queries: orderedAccounts.map((account) => ({ queryKey: ['qubic', 'balance', account.identity], From 62e88de4022c4f37fdf5e63cf6ecd70ddb8ba2e0 Mon Sep 17 00:00:00 2001 From: alez04 Date: Tue, 2 Jun 2026 17:07:53 +0300 Subject: [PATCH 2/4] fix: flag IDN/punycode origins in dapp approval and connected sites --- src/components/idn-warning-badge.tsx | 18 ++++++++++++++++++ src/lib/utils.ts | 9 +++++++++ src/locales/en.json | 1 + src/pages/settings/connected-sites.tsx | 2 ++ 4 files changed, 30 insertions(+) create mode 100644 src/components/idn-warning-badge.tsx diff --git a/src/components/idn-warning-badge.tsx b/src/components/idn-warning-badge.tsx new file mode 100644 index 0000000..c737320 --- /dev/null +++ b/src/components/idn-warning-badge.tsx @@ -0,0 +1,18 @@ +import { TriangleAlertIcon } from 'lucide-react' +import { useTranslation } from 'react-i18next' +import { hasIdnHostname } from '@/lib/utils' + +type Props = { origin: string } + +const IdnWarningBadge = ({ origin }: Props) => { + const { t } = useTranslation() + if (!hasIdnHostname(origin)) return null + return ( + + + {t('dapp.idnWarning')} + + ) +} + +export default IdnWarningBadge diff --git a/src/lib/utils.ts b/src/lib/utils.ts index f4f9db5..389b65d 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -149,6 +149,15 @@ export const formatAddressLabel = ( return `${name} (${truncated})` } +export const hasIdnHostname = (origin: string): boolean => { + try { + const { hostname } = new URL(origin) + return hostname.includes('xn--') || /[^\x00-\x7F]/.test(hostname) + } catch { + return false + } +} + export type ExplorerObject = 'tx' export const compareBigIntDesc = (a: string, b: string): number => { diff --git a/src/locales/en.json b/src/locales/en.json index be160e0..154aa88 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -471,6 +471,7 @@ "importVault": "Import vault backup" }, "dapp": { + "idnWarning": "Internationalized domain", "approval": { "title": "Connection request", "connectTitle": "Connection request", diff --git a/src/pages/settings/connected-sites.tsx b/src/pages/settings/connected-sites.tsx index 630d275..382d6b1 100644 --- a/src/pages/settings/connected-sites.tsx +++ b/src/pages/settings/connected-sites.tsx @@ -18,6 +18,7 @@ import { } from '@/lib/dapp/storage' import { useAccountNames } from '@/hooks/use-account-names' import { truncateString } from '@/lib/utils' +import IdnWarningBadge from '@/components/idn-warning-badge' const ConnectedSites = () => { const { t } = useTranslation() @@ -87,6 +88,7 @@ const ConnectedSites = () => {

{site.origin}

+

{t('settings.connectedSites.connectedAt', { date: new Date(site.connectedAt).toLocaleString(), From ecd807afef4267a634b9c20ba3ebd65c525e7b15 Mon Sep 17 00:00:00 2001 From: alez04 Date: Tue, 2 Jun 2026 17:09:00 +0300 Subject: [PATCH 3/4] fix: replace control-char regex with ASCII allowlist in hasIdnHostname --- src/lib/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 389b65d..cc3f273 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -152,7 +152,7 @@ export const formatAddressLabel = ( export const hasIdnHostname = (origin: string): boolean => { try { const { hostname } = new URL(origin) - return hostname.includes('xn--') || /[^\x00-\x7F]/.test(hostname) + return hostname.includes('xn--') || /[^a-z0-9.-]/i.test(hostname) } catch { return false } From ad958a982ce710a81c9be1f4766fb0e786c31603 Mon Sep 17 00:00:00 2001 From: alez04 Date: Tue, 2 Jun 2026 17:13:45 +0300 Subject: [PATCH 4/4] fix: clear seed and passphrase on lock in add-account onboarding flows --- src/pages/onboarding/create-wallet.tsx | 14 +++++++++++++- src/pages/onboarding/import-seed.tsx | 15 +++++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/pages/onboarding/create-wallet.tsx b/src/pages/onboarding/create-wallet.tsx index e19f06a..71f881b 100644 --- a/src/pages/onboarding/create-wallet.tsx +++ b/src/pages/onboarding/create-wallet.tsx @@ -6,7 +6,7 @@ import { useTranslation } from 'react-i18next' import { Button } from '@/components/ui/button' import { generateSeed, isSeedLike } from '@/lib/seed' import { validatePassphraseStrength } from '@/lib/passphrase' -import { setUnlocked } from '@/lib/lock' +import { isWalletLocked, setUnlocked } from '@/lib/lock' import { openBrowserVault, setOnboarded, @@ -63,6 +63,18 @@ const CreateWallet = ({ setHasConfirmedSeedBackup(false) } + useEffect(() => { + const onLock = () => { + if (!isWalletLocked()) return + setSeed('') + setPassphrase('') + setConfirmPassphrase('') + setHasConfirmedSeedBackup(false) + } + window.addEventListener('wallet-lock-updated', onLock) + return () => window.removeEventListener('wallet-lock-updated', onLock) + }, []) + useEffect(() => { let isActive = true diff --git a/src/pages/onboarding/import-seed.tsx b/src/pages/onboarding/import-seed.tsx index 5da7e35..607346e 100644 --- a/src/pages/onboarding/import-seed.tsx +++ b/src/pages/onboarding/import-seed.tsx @@ -1,4 +1,4 @@ -import { useMemo, useState } from 'react' +import { useEffect, useMemo, useState } from 'react' import { identityFromSeed } from '@qubic-labs/core' import { ArrowLeftIcon, ArrowRightIcon, KeyRoundIcon } from 'lucide-react' import { useNavigate } from 'react-router-dom' @@ -16,7 +16,7 @@ import { isAccountNameTaken, saveCachedAccounts, } from '@/lib/accounts' -import { setUnlocked } from '@/lib/lock' +import { isWalletLocked, setUnlocked } from '@/lib/lock' import { openBrowserVault, setOnboarded, @@ -73,6 +73,17 @@ const ImportSeed = ({ setDerivedIdentity(null) } + useEffect(() => { + const onLock = () => { + if (!isWalletLocked()) return + setSeed('') + setPassphrase('') + setDerivedIdentity(null) + } + window.addEventListener('wallet-lock-updated', onLock) + return () => window.removeEventListener('wallet-lock-updated', onLock) + }, []) + const handleSeedChange = (value: string) => { setSeed(normalizeSeedInput(value)) if (step === 1 && status) {