A fake human-verification page persuaded a Fomo user to install a malicious browser bookmark and execute it on a logged-in Fomo page, according to an analysis by SlowMist. The user reported losing approximately $48,000, despite not connecting a wallet, granting an on-chain approval, or entering a seed phrase or private key.
The important distinction is that this attack targeted browser-held login credentials and embedded-wallet data, rather than asking the user to sign a transaction directly. SlowMist reconstructed the credential-collection script, but said the precise method used to complete the subsequent asset transfers remained unconfirmed.
Source publication: October 8, 2026, at 19:00 UTC+8. Original authors: Yao and Lisa; editor: 77. This article summarizes that dated investigation, not a newly verified incident.
How the fake verification worked
According to the user’s account and screenshots reviewed by SlowMist, the user followed a project-website link displayed on Fomo’s MOONLET token details page. It led to voltage[.]family, where the /app page presented nine icons and asked the user to:
- Find an animal with four legs.
- Drag its icon into the browser’s bookmarks bar.
- Click the resulting bookmark three times.
The bookmark was named “Triple click to verify.” Instead of a normal web address, it contained code beginning with javascript:—a bookmarklet. Clicking such a bookmark runs its JavaScript in the context of the current page.
SlowMist found that choosing a particular animal did not change the outcome. The site’s fomo-track.js script repeatedly replaced the icon links with the same malicious bookmark code, including during page changes, timer events, mouse presses and drag operations.
The intended next step was to get the user to run that bookmark on a logged-in Fomo page. A subsequent /app/live page imitated a trading terminal, but labeled its market data as simulated; its connect-wallet button only displayed a message. SlowMist assessed these elements as credibility-building props.
Merely opening the phishing website was not equivalent to executing the credential-collection code. The bookmark needed to run in a page context that satisfied its hostname check and exposed the targeted storage.
What the bookmark tried to collect
The compressed bookmark contained more than 8,000 characters. Its initial check used location.hostname.includes("fomo.family"), not an exact hostname comparison. As SlowMist noted, that condition could match other hostnames containing the same string—not just Fomo’s domain and legitimate subdomains.
Once running in a matching context, the script searched:
- Local storage and session storage: It matched keys against terms including
privy,wallet,share,secret,seed,mnemon,turnkey,dynamic,fomoandmfa. If a key did not match, it examined the first 300 characters of its value. Matching values were retained up to 4,000 characters. - IndexedDB: It enumerated accessible databases and object stores, read records with
getAll(), and organized results by database and store name. This collection stage had a four-second timeout. - Authentication tokens: It prioritized
privy:tokenandprivy:refresh_token, including token values wrapped in JSON. Broader fallback searches looked for other token fields and JWT-like strings beginning witheyJ. Those fallback matches were only suspected tokens, not necessarily valid credentials.
In an embedded-wallet setup, such data may relate to wallet access, recovery or key material. SlowMist warned that stolen credentials could potentially enable wallet takeover, private-key export or transactions. The supplied script demonstrated collection and exfiltration; it did not establish which downstream method actually moved the victim’s funds.
The MFA behavior needs careful interpretation
The script also contained logic for interacting with Privy’s authentication service. Using an access token, application ID and client ID, it requested the user’s account information and inspected mfa_methods or mfaMethods. It included refresh-token handling to retry after a 401 response.
A counterintuitive condition matters here: the MFA enrollment branch ran only when the returned MFA-methods array was nonempty, meaning at least one method was already registered. If the array was empty, the script skipped that branch.
When triggered, the branch created a nearly transparent 4×4-pixel iframe loading Privy’s embedded-wallets page and used postMessage requests to attempt TOTP enrollment. If initialization returned a secret, the script could calculate a six-digit code using 30-second time steps and HMAC-SHA1, then submit an enrollment request.
However, receiving an initialization secret did not prove that enrollment succeeded. Nor did the script’s handling of errors containing terms such as “already,” “enrolled” or “duplicate.” Confirmation would require server-side records.
The affected user said they signed in through Google and had not enabled two-factor authentication. SlowMist therefore considered it likely that this MFA branch did not execute. The storage-collection and exfiltration paths were independent and could still run.
Where the data was sent—and what remains unknown
The script packaged collected storage, IndexedDB records and MFA results into a base64url-encoded payload. If it exceeded 11,000 characters, it reduced the IndexedDB content first, then narrowed local-storage data to three key fields if necessary. A 20-second fallback prevented collection from delaying transmission indefinitely.
The destination was noisy-heart-5856[.]zmfkc29[.]workers[.]dev. The script used an early fetch request if it obtained a TOTP initialization secret, and a browser redirect carrying tokens and collected data in URL parameters.
SlowMist’s non-destructive tests found that the endpoint returned 302 redirects to the phishing site for several request types, while POST /visit returned 204. Those responses were consistent with a collection-and-redirect design, but did not prove that the server stored the submitted data.
A code comment described a tracker-to-Cloudflare-Worker-to-panel-to-Telegram chain. SlowMist treated that as a lead left by the sample’s author, not independently confirmed backend evidence. Actual credential replay and the identity of whoever initiated later transactions still required server logs and on-chain investigation.
What the fund tracing showed
Separately from the user’s approximate $48,000 loss estimate, SlowMist reported that information supplied by the victim identified 45,106.85 USDC withdrawn in three transfers to:
D783JqupQ2FYhkxUfGEd1gaFEoAJDXRX1NEb4aVH2hZ6
Using MistTrack, SlowMist found that this address had been active since September 17 and had already made frequent USDC–SOL exchanges before receiving the victim’s funds. The team suspected other victims, but did not establish that as a confirmed fact.
The address’s broader activity included swaps mostly through Jupiter Aggregator, transfers split among intermediate addresses, cross-chain movements through Relay.link, and incoming bridged funds through deBridge. SlowMist reported total transfers of 1,568.33 SOL to Privacy Cash Pool, which it identified as the address’s main laundering outlet.
Some funds also reached addresses associated with Stake and Winna. Reported Winna-related movements included deposits of 11.34 SOL and 1,500 USDC, and receipt of 7,199.81 USDC from a Winna hot wallet. These observations describe the address’s overall activity; they should not be read as a transaction-by-transaction tracing of every dollar lost by this user.
What users should do
The source’s practical warning is straightforward: a legitimate human-verification task should not require installing a JavaScript bookmark and executing it on a wallet or trading page. Stop if a page asks you to do this, and remove unfamiliar javascript: bookmarks.
If you have already executed a suspicious bookmark, SlowMist recommends:
- Use a trusted device and official support channels. Revoke suspicious sessions and relevant authorizations where the platform supports doing so.
- Review authentication settings. Check for unfamiliar authenticators and remove them with the platform’s assistance. If you use Google or another identity provider to sign in, check that account’s security too.
- Do not assume a password change ends access. Whether existing sessions and refresh tokens become invalid depends on the platform’s implementation.
- If evidence indicates seed-phrase or private-key exposure, move remaining assets to a newly generated wallet.
- Preserve evidence: the suspicious URL, bookmark contents, execution time and transaction records.
Enable platform-supported MFA for important accounts, but do not treat it as a substitute for avoiding untrusted code execution.
What builders should review
For embedded-wallet integrations, SlowMist recommends independent verification and risk controls for MFA enrollment, replacement, recovery and fund transfers—not reliance on an existing session alone.
Other priorities include user-visible session revocation, alerts for unusual devices and MFA changes, server-side credential revocation, and reducing sensitive or long-lived data in browser storage. Projects should also review external links and user-generated content, and explicitly warn users against executing unfamiliar bookmarks or code while logged in.
The central lesson is not that every wallet loss requires an approval or a disclosed seed phrase. A compromised authenticated browser session can expose another route to wallet access—and the exact consequences must be established from evidence, not inferred from the phishing script alone.