Created
June 11, 2026 23:52
-
-
Save Isolyth/4685e7a55569a95dffdf9cc8319e60e8 to your computer and use it in GitHub Desktop.
kickbacks.ai realistic multi-window saturation test (impression-integrity PoC)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // 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, 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). | |
| // * 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. | |
| // * 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 view_tick is true accrued wall-clock time, not fabricated. | |
| // * 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. | |
| // | |
| // Requires explicit opt-in so it can never run by accident: | |
| // export KICKBACKS_TOKEN='...' | |
| // node attack-real.mjs --yes-i-own-this-account | |
| // | |
| // Environment: | |
| // KICKBACKS_TOKEN bearer token (required) | |
| // KICKBACKS_BASE backend base URL (default: live) | |
| // DURATION_MS test duration in ms (default 120_000 = 2 min) | |
| // KICKBACKS_WINDOW_COUNT window count (default 4) | |
| // KICKBACKS_QUIET "1" to suppress per-event logging | |
| import { randomUUID } from "node:crypto"; | |
| // ── 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 TOKEN = process.env.KICKBACKS_TOKEN; | |
| if (!TOKEN) { console.error("set KICKBACKS_TOKEN (run signin.mjs or signin-email.mjs first)"); 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) : 4; | |
| const QUIET = process.env.KICKBACKS_QUIET === "1"; | |
| const CLIENT_ID = `install-${randomUUID().slice(0, 4)}`; | |
| // ── faithful constants (cliTick.ts / statusBarAd.ts) ───────────────────────── | |
| const POLL_MS = 1_000; | |
| const VIEW_TICK_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_MS + Math.random() * 800; // always >= 5000ms | |
| // ── helpers ───────────────────────────────────────────────────────────────── | |
| const authed = (extra = {}) => ({ authorization: `Bearer ${TOKEN}`, ...extra }); | |
| async function getPortfolio() { | |
| const r = await fetch(`${BASE}/v1/portfolio?claude_code_version=${CC_VERSION}`, { | |
| headers: authed(), | |
| }); | |
| if (!r.ok) throw new Error(`portfolio HTTP ${r.status}`); | |
| return r.json(); | |
| } | |
| async function getEarnings() { | |
| const r = await fetch(`${BASE}/v1/earnings`, { headers: authed() }); | |
| 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, | |
| ...(visibleMs != null | |
| ? { | |
| visible_ms: Math.round(visibleMs), | |
| view_pct: 100, | |
| viewable: true, | |
| } | |
| : {}), | |
| session_token: ad.session_token, | |
| }; | |
| const t0 = performance.now(); | |
| const r = await fetch(`${BASE}/v1/metrics`, { | |
| method: "POST", | |
| headers: authed({ "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) | |
| } | |
| // ── one "window" pinned to one ad ──────────────────────────────────────────── | |
| async function runWindow(ad, surface, deadline, counters) { | |
| let showCount = 0; | |
| while (Date.now() < deadline) { | |
| const showLen = sampleShowLen(); | |
| const showStart = Date.now(); | |
| const showDeadline = showStart + showLen; | |
| // continuous-show cap: if this show exceeds 60s, cut at 60s then rest 20s | |
| const effectiveShowMax = Math.min(showDeadline, showStart + AD_SHOW_MAX_MS); | |
| await fireEvent(ad, "impression_rendered", { surface }); | |
| counters.rendered++; | |
| let lastTick = showStart; | |
| let nextGap = tickGap(); | |
| let accruedMs = 0; | |
| while (Date.now() < effectiveShowMax && Date.now() < deadline) { | |
| await sleep(180); // ~ the 1s poll, finer grain | |
| const now = Date.now(); | |
| const delta = now - lastTick; | |
| // simulate the VISIBLE_GAP_CAP_MS clamp the real client applies | |
| const cappedDelta = Math.min(delta, VISIBLE_GAP_CAP_MS); | |
| accruedMs += cappedDelta; | |
| lastTick = now; | |
| if (now - showStart >= nextGap) { | |
| const res = await fireEvent(ad, "view_tick", { surface, visibleMs: accruedMs }); | |
| counters.viewTick++; | |
| if (res.didCredit) counters.credited++; | |
| if (!res.didCredit) counters.rejected++; | |
| if (res.reason && res.reason !== "credited" && res.reason !== "ok") { | |
| counters.reasons[res.reason] = (counters.reasons[res.reason] || 0) + 1; | |
| } | |
| nextGap += tickGap(); | |
| } | |
| } | |
| const actualShowMs = Date.now() - showStart; | |
| const res = await fireEvent(ad, "impression_viewable", { | |
| surface, | |
| visibleMs: actualShowMs, | |
| }); | |
| counters.viewable++; | |
| if (res.didCredit) counters.credited++; | |
| if (!res.didCredit) counters.rejected++; | |
| if (res.reason && res.reason !== "credited" && res.reason !== "ok") { | |
| counters.reasons[res.reason] = (counters.reasons[res.reason] || 0) + 1; | |
| } | |
| showCount++; | |
| // if we hit the 60s cap, enforce the 20s rest | |
| const hitCap = actualShowMs >= AD_SHOW_MAX_MS - 500; | |
| if (hitCap) { | |
| const restUntil = Date.now() + AD_REST_MS; | |
| while (Date.now() < restUntil && Date.now() < deadline) await sleep(200); | |
| } else { | |
| // normal think -> idle gap | |
| const idleMs = 800 + Math.random() * 3_200; | |
| const idleUntil = Date.now() + idleMs; | |
| while (Date.now() < idleUntil && Date.now() < deadline) await sleep(200); | |
| } | |
| } | |
| counters.shows += showCount; | |
| } | |
| // ── main ───────────────────────────────────────────────────────────────────── | |
| async function main() { | |
| console.log(`\n[attack-real] base = ${BASE}`); | |
| console.log(`[attack-real] duration = ${DURATION_MS}ms client_id = ${CLIENT_ID}`); | |
| 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 portfolio = await getPortfolio(); | |
| const ads = portfolio.ads || []; | |
| if (!ads.length) { console.error("[attack-real] empty portfolio"); process.exit(1); } | |
| const K = FORCED_K ?? ads.length; | |
| const windows = ads.slice(0, K); | |
| console.log(`[attack-real] queue depth K = ${ads.length} windows = ${K}`); | |
| console.log(`[attack-real] ads = [${windows.map((a) => a.ad_id).join(", ")}]\n`); | |
| const counters = { | |
| rendered: 0, viewTick: 0, viewable: 0, | |
| credited: 0, rejected: 0, shows: 0, reasons: {}, | |
| }; | |
| const deadline = Date.now() + DURATION_MS; | |
| const startWall = Date.now(); | |
| console.log("[attack-real] firing windows … (Ctrl-C to abort)\n"); | |
| // run all windows concurrently on the SAME account | |
| await Promise.all( | |
| windows.map((ad, i) => | |
| runWindow(ad, i % 2 ? "statusline" : "statusbar", deadline, counters) | |
| ) | |
| ); | |
| const wallElapsed = Date.now() - startWall; | |
| // settle + final earnings | |
| 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; | |
| 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(` 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}`); | |
| } | |
| } | |
| // verdict | |
| 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); }); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
That was fast 🫨