Is OptimAI Lite Node safe?
OptimAI Lite Node collects device fingerprints and reports uptime to api.optimai.network every 10–15 minutes in exchange for passive-income rewards.
When a user authenticates, the extension gathers hardware and browser details — CPU cores, memory, screen dimensions, language, and timezone — and transmits them to api.optimai.network. It then maintains a persistent WebSocket connection to ws.optimai.network and sends periodic uptime pings; each ping response returns a server-assigned user_ip_id that the extension stores locally. All outbound payloads are encoded with a multi-step custom obfuscation scheme using a hardcoded HMAC-SHA256 secret.
Who publishes itOptimAI Network - 1 other listing from the same operator, none carrying a finding
OptimAI Network - 1 other listing from the same operator, none carrying a finding
What this publisher told the store about itself, and the other listings that told it the same thing.
Same store account
1 other listing published from this account, 10k+ users between them, none of them carrying a finding.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Hardcoded HMAC Credential and Multi-Step Obfuscation on All API Traffic
OptimAI Lite Node encodes outbound request bodies via a 3-step pipeline, then base64-encodes them.
A hardcoded 30-character string in background.js is the HMAC-SHA256 key, so anyone with the source can forge signatures or decode responses.
- Severity
- Medium unwanted
- Type
- Unexpected
- CWE
- CWE-506
- Source
- Dynamic sandbox
You install OptimAI Lite Node and sign in.
The extension sends your device fingerprint to api.optimai.network, encoded through a custom obfuscation pipeline and signed with a hardcoded key embedded in the extension's code.
Every API request body is passed through vs() → Us() → Os() → btoa(). Server responses go through the inverse gr(). The HMAC-SHA256 signing key is a plain-text constant visible to anyone who downloads the extension.
Obfuscation pipeline, shipped source vs deobfuscated
Step 1 — vs(): Fibonacci codepoint shift
background.js:4161,4174// ks(i) returns Fibonacci(i) % 20function ks(e) { let t = 0, i = 1; for (let s = 0; s < e; s++) [t, i] = [i, t + i]; return t % 20;}// Each character's codepoint is increased by Fibonacci(index) mod 20function vs(e) { return [...e].map((t, i) => String.fromCharCode(t.charCodeAt(0) + ks(i))).join("");}Step 2 — Us(): XOR each character by its index mod 256
background.js:4171function Us(e) { return [...e].map((t, i) => String.fromCharCode((t.charCodeAt(0) ^ i % 256) & 255) ).join("");}Step 3 — Os(): swap adjacent character pairs
background.js:4166function Os(e) { const t = [...e]; for (let i = 0; i < t.length - 1; i += 2) [t[i], t[i + 1]] = [t[i + 1], t[i]]; return t.join("");}Combined pipeline — pr() and response decoder gr()
background.js:4177,4180// Encode: vs → Us → Os → btoafunction pr(e) { return btoa(Os(Us(vs(e))));}// Decode response: atob → drop every 5th char → reverse → XOR pairs as hexfunction gr(e) { const s = atob(e) .split("") .filter((u, d) => (d + 1) % 5 !== 0) .join("") .split("") .reverse() .join(""); const a = 7; return s.match(/.{1,2}/g) .map((u, d) => String.fromCharCode(parseInt(u, 16) ^ a + d)) .join("");}Hardcoded HMAC-SHA256 signing key
HMAC-SHA256 signing using the hardcoded credential
background.js:4344,4378var an = { CEB_CLIENT_APP_ID: "TLG_MINI_APP_V1", CEB_CLIENT_SECRET: "D1A167BD1346DDF2357DA5A2F2F2F" };const Er = an.CEB_CLIENT_SECRET, Hs = an.CEB_CLIENT_APP_ID;async function Gs(e) { try { const t = { client_app_id: Hs || "", timestamp: Date.now(), device_info: e }; const i = Ar(t); // deterministic JSON serialization const s = xr(Er); // encode the hardcoded secret const a = await crypto.subtle.importKey( "raw", s, { name: "HMAC", hash: "SHA-256" }, false, ["sign"] ); const c = await crypto.subtle.sign("HMAC", a, xr(i)); const u = Vs(new Uint8Array(c)); // hex-encode signature return btoa(Ar({ ...t, signature: u })); } catch { return ""; }}Decodes OptimAI API request bodies and response payloads using the same algorithm embedded in the extension. Also re-derives the HMAC-SHA256 signature for any device_info payload using the hardcoded HMAC credential.
- Node.js 18+
#!/usr/bin/env node// Reproducer: decode OptimAI Lite Node API traffic// Requires Node.js 18+ (crypto.subtle available via globalThis)const { createHmac } = require('crypto');const CEB_CLIENT_SECRET = 'D1A167BD1346DDF2357DA5A2F2F2F';const CEB_CLIENT_APP_ID = 'TLG_MINI_APP_V1';// --- encoding pipeline (matches pr() in background.js:4177) ---function fibonacci_mod20(i) { let a = 0, b = 1; for (let s = 0; s < i; s++) [a, b] = [b, a + b]; return a % 20;}function vs(str) { // Step 1: shift each char's codepoint by Fibonacci(index) mod 20 return [...str].map((c, i) => String.fromCharCode(c.charCodeAt(0) + fibonacci_mod20(i)) ).join('');}function Us(str) { // Step 2: XOR each char by its index mod 256 return [...str].map((c, i) => String.fromCharCode((c.charCodeAt(0) ^ (i % 256)) & 0xFF) ).join('');}function Os(str) { // Step 3: swap adjacent character pairs const chars = [...str]; for (let i = 0; i < chars.length - 1; i += 2) [chars[i], chars[i + 1]] = [chars[i + 1], chars[i]]; return chars.join('');}function pr(plaintext) { return Buffer.from(Os(Us(vs(plaintext)))).toString('base64');}// --- decoding pipeline (matches gr() in background.js:4180) ---function gr(encoded) { const raw = Buffer.from(encoded, 'base64').toString('latin1'); const stripped = raw.split('').filter((_, d) => (d + 1) % 5 !== 0).join(''); const reversed = stripped.split('').reverse().join(''); const a = 7; const pairs = reversed.match(/.{1,2}/g) || []; return pairs.map((pair, d) => String.fromCharCode(parseInt(pair, 16) ^ (a + d)) ).join('');}// --- HMAC-SHA256 signing (matches Gs() in background.js:4378) ---function sign_device_info(device_info) { const payload = JSON.stringify({ client_app_id: CEB_CLIENT_APP_ID, timestamp: Date.now(), device_info }); const sig = createHmac('sha256', CEB_CLIENT_SECRET).update(payload).digest('hex'); return Buffer.from(JSON.stringify({ ...JSON.parse(payload), signature: sig })).toString('base64');}// --- demo ---const sample_payload = JSON.stringify({ user_id: 'u-1234abcd', device_id: 'dev-0000beef', device_type: 'extension', duration: 3600, timestamp: 1749200000000});const encoded = pr(sample_payload);console.log('=== Encoded (what the extension sends) ===');console.log(encoded);console.log();console.log('=== pr() is NOT encryption — decoded back to original ===');// Note: gr() is the server-response decoder, not exact inverse of pr(),// so we demonstrate reversibility via direct reversalconst reversed_Us = (str) => Us(str); // Us is self-inverse (XOR)const reversed_Os = Os; // Os is also self-inverse (adjacent swap)const reversed_vs = (str) => [...str].map((c, i) => String.fromCharCode(c.charCodeAt(0) - fibonacci_mod20(i))).join('');const decoded_sample = reversed_vs(reversed_Us(reversed_Os(Buffer.from(encoded, 'base64').toString())));console.log('Decoded:', decoded_sample);console.log();console.log('=== Forged HMAC signature for arbitrary device_info ===');const forged_token = sign_device_info({ cpu_cores: 4, memory_gb: 8, browser_name: 'chrome', device_type: 'extension', language: 'en-US', timezone: 'Europe/London' });console.log('x-client-authentication:', forged_token);- 1Run: node decode-optimai-traffic.js
- 2'encoded' matches what the extension sends to api.optimai.network.
- 3It decodes back to the original JSON, no credential.
- 4The forged HMAC token shows the key enables signature replication.
- api.optimai.network
Primary API endpoint. Receives obfuscated device registration and uptime payloads via /devices/register-v2 and the uptime log path. Operated by OptimAI.
Where it sends data
Destinations our analysis observed OptimAI Lite Node contacting. Sending data somewhere is not a finding on its own - an extension that syncs your settings has to talk to its own server - but it is where your data can go, and who else it goes to.
- api.optimai.network
OptimAI Lite Node sends data to api.optimai.network. No other extension we have analysed sends data here.
- ws.optimai.network
OptimAI Lite Node sends data to ws.optimai.network. No other extension we have analysed sends data here.