Tank · Code Alliance Developers
Termux Arsenalby Tank · Code Alliance
snippets · console · eruda

Snippets de auditoria.Cole no DevTools (F12) ou no Eruda mobile e mapeie fluxos, tokens, endpoints, CSP e fraquezas.

⚠ uso éticoRode apenas em sites seus, em ambiente de lab, em CTF, ou dentro do escopo de um bug bounty autorizado. Snippets marcados comoexpõe segredomostram dados sensíveis no console — cuidado com screenshot / gravação de tela.
▸ como abrir o console (Eruda no mobile, DevTools no PC)

Desktop: F12 → aba Console → cole → Enter.

Mobile (Eruda): instale via bookmarklet — crie um favorito com a URL abaixo, abra o site alvo e toque no favorito. O painel do Eruda aparece; vá em Console ou Snippets e cole.

$ javascript:(function(){var s=document.createElement('script');s.src='https://cdn.jsdelivr.net/npm/eruda';document.body.appendChild(s);s.onload=function(){eruda.init()};})();

Dica: no Eruda, a aba Snippets salva seus favoritos — cole cada um daqui uma vez e reuse depois.

gerador · fluxo do usuário

Monte um snippet + checklist sob medida

Marque os fluxos que quer inspecionar. Gera um único JS pra colar no console (grava submits, fetches, cliques e uploads em window.__flow), + um prompt pronto pra jogar num LLM analisar, + checklist manual de validações fracas, autorização e exposições.

// === Gerador de Fluxo do Usuário (Termux Arsenal) ===
// Fluxos ativos: Login / autenticação, Checkout / pagamento, Cliques / interações
// Uso: cole no console, interaja com o site, depois rode:  window.__flow
(function(){
  if (window.__flow) { console.log('já rodando — window.__flow', window.__flow); return; }
  window.__flow = { login:[], checkout:[], cliques:[] };
  // hook de login
  document.addEventListener('submit', (e) => {
    const f = e.target;
    if (!f.querySelector('input[type=password]')) return;
    const data = Object.fromEntries(new FormData(f).entries());
    console.warn('[LOGIN submit]', { action: f.action, method: f.method, data });
    window.__flow.login.push({ t: Date.now(), data, action: f.action });
  }, true);

  // hook de checkout
  const _fetch = window.fetch;
  window.fetch = function(u, o) {
    if (/pay|checkout|order|cart|charge/i.test(String(u))) {
      console.warn('[CHECKOUT fetch]', u, o?.body);
      window.__flow.checkout.push({ t: Date.now(), url: String(u), body: o?.body });
    }
    return _fetch.apply(this, arguments);
  };

  // hook de cliques
  document.addEventListener('click', (e) => {
    const t = e.target.closest('button,a,[role=button]');
    if (!t) return;
    const info = { tag: t.tagName, text: (t.innerText||'').slice(0,60), href: t.href, sel: cssPath(t) };
    console.log('[CLICK]', info);
    window.__flow.cliques.push({ t: Date.now(), ...info });
  }, true);
  function cssPath(el){ if(!el||el.nodeType!==1)return''; const p=[]; while(el&&el.nodeType===1&&p.length<5){ let s=el.nodeName.toLowerCase(); if(el.id){s+='#'+el.id; p.unshift(s); break;} else if(el.className){s+='.'+String(el.className).trim().split(/\s+/).slice(0,2).join('.')} p.unshift(s); el=el.parentNode; } return p.join('>'); }

  // dump helper
  window.__dumpFlow = () => {
    const out = JSON.stringify(window.__flow, null, 2);
    console.log(out);
    try { navigator.clipboard.writeText(out); console.log('%c✓ copiado pro clipboard', 'color:#0f0'); } catch(_){}
    return window.__flow;
  };
  console.log('%c▸ fluxos ativos. Interaja e rode window.__dumpFlow()', 'color:#0ff;font-weight:bold');
})();

depois de interagir com o site → rode window.__dumpFlow() pra copiar o JSON e colar no prompt.

20 snippets

Fingerprint completo do site

reconleitura passiva

▸ objetivo: Ter em 1 tela: framework, libs, versão, meta, workers.

▸ o que faz: Detecta React/Vue/Angular/Next, jQuery, GA, GTM, Sentry, Service Workers e vars globais suspeitas.

lê: window.* · navigator.serviceWorker · document.querySelectorAll('script,meta')
console · javascript
(async () => {
  const w = window;
  const has = (k) => k in w;
  const fw = {
    React: !!w.React || !!document.querySelector('[data-reactroot],#__next,#root'),
    Next: !!w.__NEXT_DATA__,
    Vue: !!w.Vue || !!document.querySelector('[data-v-app]'),
    Nuxt: !!w.__NUXT__,
    Angular: !!w.getAllAngularRootElements,
    jQuery: has('jQuery') ? w.jQuery.fn.jquery : false,
    GTM: has('google_tag_manager'),
    GA: has('ga') || has('gtag'),
    Sentry: has('Sentry'),
    Segment: has('analytics'),
    Stripe: has('Stripe'),
    Firebase: has('firebase'),
    Supabase: has('supabase'),
  };
  const sw = await navigator.serviceWorker?.getRegistrations?.() ?? [];
  const scripts = [...document.scripts].map(s => s.src).filter(Boolean);
  const metas = [...document.querySelectorAll('meta')].map(m => ({
    name: m.name || m.getAttribute('property'),
    content: m.content,
  })).filter(m => m.name);
  const globals = Object.keys(w).filter(k =>
    /token|api|key|secret|auth|user|session|jwt|csrf/i.test(k)
  );
  console.group('%c▸ FINGERPRINT', 'color:#00ff88;font-weight:bold');
  console.table(fw);
  console.log('service workers:', sw.map(r => r.scope));
  console.log('scripts externos:', scripts);
  console.log('metas:', metas);
  console.warn('globais suspeitos:', globals);
  console.groupEnd();
  return { fw, sw: sw.length, scripts: scripts.length, metas: metas.length, globals };
})();

Extrair endpoints e URLs de todo JS carregado

recongera tráfego

▸ objetivo: Descobrir /api/*, GraphQL, S3, CDNs escondidos em bundles.

▸ o que faz: Baixa cada <script src> e regex-eia strings /url/http.

lê: fetch de cada script src do domínio atual
console · javascript
(async () => {
  const origin = location.origin;
  const scripts = [...document.scripts].map(s => s.src).filter(s => s.startsWith(origin));
  const rx = /(https?:\/\/[^"'\s<>]{4,200}|\/[a-zA-Z0-9_\-\/\.]{3,120}\?[^"'\s<>]{0,120}|\/api\/[a-zA-Z0-9_\-\/\.]{2,120})/g;
  const found = new Set();
  for (const src of scripts) {
    try {
      const txt = await (await fetch(src)).text();
      (txt.match(rx) || []).forEach(u => found.add(u));
    } catch (e) { console.warn('fail', src, e.message); }
  }
  const arr = [...found].sort();
  console.group('%c▸ ENDPOINTS ENCONTRADOS: ' + arr.length, 'color:#00ffaa;font-weight:bold');
  arr.forEach(u => console.log(u));
  console.groupEnd();
  copy?.(arr.join('\n'));
  return arr;
})();

Rotas de SPA (React Router / Next / Vue)

reconleitura passiva

▸ objetivo: Listar todas as rotas registradas no client-side router.

▸ o que faz: Vasculha __NEXT_DATA__, __vue_app__, react-router history.

lê: window.__NEXT_DATA__ · window.__NUXT__ · history.state
console · javascript
(() => {
  const out = { next: null, nuxt: null, history: history.state };
  if (window.__NEXT_DATA__) {
    out.next = {
      page: __NEXT_DATA__.page,
      buildId: __NEXT_DATA__.buildId,
      pageProps: Object.keys(__NEXT_DATA__.props?.pageProps ?? {}),
    };
    // manifest de páginas
    fetch('/_next/static/' + __NEXT_DATA__.buildId + '/_buildManifest.js')
      .then(r => r.text()).then(t => console.log('%cbuildManifest:', 'color:#0af', t));
  }
  if (window.__NUXT__) out.nuxt = { routePath: __NUXT__.routePath, state: Object.keys(__NUXT__.state || {}) };
  console.table(out);
  return out;
})();

Dump completo de localStorage + sessionStorage + cookies

storageexpõe segredo

▸ objetivo: Ver TUDO que o site salvou no seu navegador.

▸ o que faz: Imprime chave→valor de todos os storages + cookies do domínio.

lê: localStorage · sessionStorage · document.cookie
console · javascript
(() => {
  const dump = (s, name) => {
    const o = {};
    for (let i = 0; i < s.length; i++) { const k = s.key(i); o[k] = s.getItem(k); }
    console.group('%c▸ ' + name + ' (' + s.length + ')', 'color:#ffaa00;font-weight:bold');
    console.table(o);
    console.groupEnd();
    return o;
  };
  const ls = dump(localStorage, 'localStorage');
  const ss = dump(sessionStorage, 'sessionStorage');
  const cookies = Object.fromEntries(document.cookie.split(';').map(c => {
    const [k, ...v] = c.trim().split('='); return [k, v.join('=')];
  }).filter(([k]) => k));
  console.group('%c▸ cookies', 'color:#ffaa00;font-weight:bold');
  console.table(cookies);
  console.groupEnd();
  return { ls, ss, cookies };
})();

Listar bancos IndexedDB + object stores

storageexpõe segredo

▸ objetivo: Descobrir dados offline (PWA, cache de mensagens, tokens).

▸ o que faz: Enumera todos os DBs e stores acessíveis pelo origin.

lê: indexedDB.databases() · conteúdo de cada store
console · javascript
(async () => {
  const dbs = await indexedDB.databases();
  const out = [];
  for (const meta of dbs) {
    const db = await new Promise((res, rej) => {
      const r = indexedDB.open(meta.name, meta.version);
      r.onsuccess = () => res(r.result); r.onerror = () => rej(r.error);
    });
    const stores = [...db.objectStoreNames];
    const rows = {};
    for (const s of stores) {
      const tx = db.transaction(s, 'readonly').objectStore(s);
      rows[s] = await new Promise(res => { const r = tx.getAll(); r.onsuccess = () => res(r.result); });
    }
    out.push({ name: meta.name, version: meta.version, stores, rows });
    db.close();
  }
  console.group('%c▸ IndexedDB', 'color:#ffaa00;font-weight:bold');
  console.log(out);
  console.groupEnd();
  return out;
})();

Scanner de segredos (JWT, API keys, PII) em todo storage

storageexpõe segredo

▸ objetivo: Alertar sobre token, chave, cartão, CPF salvos no client.

▸ o que faz: Regex em localStorage/sessionStorage/cookies/HTML do DOM.

lê: storages · document.documentElement.outerHTML
console · javascript
(() => {
  const patterns = {
    JWT: /eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{5,}/g,
    AWS: /AKIA[0-9A-Z]{16}/g,
    Google: /AIza[0-9A-Za-z_\-]{35}/g,
    Stripe_pk: /pk_(live|test)_[0-9A-Za-z]{20,}/g,
    Stripe_sk: /sk_(live|test)_[0-9A-Za-z]{20,}/g,
    Slack: /xox[baprs]-[0-9A-Za-z\-]{10,}/g,
    Bearer: /Bearer\s+[A-Za-z0-9._\-]{20,}/g,
    UUID: /\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/g,
    CPF: /\b\d{3}\.\d{3}\.\d{3}-\d{2}\b/g,
    Cartao: /\b(?:\d[ -]?){13,19}\b/g,
    Email: /\b[\w.+-]+@[\w.-]+\.[a-z]{2,}\b/gi,
  };
  const sources = {
    localStorage: JSON.stringify(Object.entries(localStorage)),
    sessionStorage: JSON.stringify(Object.entries(sessionStorage)),
    cookies: document.cookie,
    dom: document.documentElement.outerHTML.slice(0, 500000),
  };
  const hits = [];
  for (const [where, txt] of Object.entries(sources)) {
    for (const [name, rx] of Object.entries(patterns)) {
      const m = txt.match(rx); if (m) hits.push({ where, name, sample: m.slice(0, 3), total: m.length });
    }
  }
  console.group('%c▸ SECRETS SCAN', 'color:#ff3366;font-weight:bold');
  console.table(hits);
  console.groupEnd();
  return hits;
})();

Sniffer live de fetch + XHR (URL, headers, body, resposta)

networkleitura passiva

▸ objetivo: Ver TODA requisição que o site fizer daqui pra frente.

▸ o que faz: Faz monkey-patch em window.fetch e XMLHttpRequest; loga tudo colorido.

lê: intercepta chamadas do próprio site
console · javascript
(() => {
  if (window.__snifferOn) { console.warn('sniffer já ativo'); return; }
  window.__snifferOn = true;
  window.__requests = [];
  const of = window.fetch;
  window.fetch = async function (...a) {
    const t0 = performance.now();
    const req = { type: 'fetch', url: (typeof a[0] === 'string' ? a[0] : a[0].url), init: a[1] || {} };
    const res = await of.apply(this, a);
    const clone = res.clone();
    let body; try { body = await clone.text(); } catch {}
    req.status = res.status; req.ms = (performance.now() - t0).toFixed(1); req.body = body?.slice(0, 400);
    console.log('%c[fetch]', 'color:#0f0', req.status, req.url, req.ms + 'ms', req);
    window.__requests.push(req);
    return res;
  };
  const OX = window.XMLHttpRequest.prototype.open;
  const SX = window.XMLHttpRequest.prototype.send;
  window.XMLHttpRequest.prototype.open = function (m, u) { this.__u = u; this.__m = m; return OX.apply(this, arguments); };
  window.XMLHttpRequest.prototype.send = function (b) {
    this.addEventListener('loadend', () => {
      const req = { type: 'xhr', method: this.__m, url: this.__u, status: this.status, body: this.responseText?.slice(0, 400) };
      console.log('%c[xhr]', 'color:#0ff', req.status, req.url, req);
      window.__requests.push(req);
    });
    return SX.apply(this, arguments);
  };
  console.log('%c▸ sniffer ativo. Use window.__requests pra listar.', 'color:#0f0;font-weight:bold');
})();

Repetir última requisição alterando parâmetro

networkgera tráfego

▸ objetivo: IDOR / mass-assignment / tampering rápido.

▸ o que faz: Pega o último item de window.__requests e refaz com body/URL modificado.

lê: window.__requests (do sniffer)
console · javascript
(async ({ patchUrl = (u) => u, patchInit = (i) => i } = {}) => {
  const r = window.__requests?.slice().reverse().find(x => x.type === 'fetch');
  if (!r) return console.warn('rode o sniffer primeiro e faça uma ação no site');
  const url = patchUrl(r.url);
  const init = patchInit({ ...r.init, method: r.init.method || 'GET' });
  console.log('replay →', url, init);
  const res = await fetch(url, init);
  const txt = await res.text();
  console.log('status', res.status, 'body:', txt.slice(0, 800));
  return { status: res.status, body: txt };
})({
  // exemplo: trocar id=1 por id=2
  patchUrl: (u) => u.replace(/id=\d+/, 'id=2'),
  patchInit: (i) => i,
});

Sondar CORS de um endpoint interno

networkgera tráfego

▸ objetivo: Descobrir se um endpoint retorna dado pra qualquer origem.

▸ o que faz: Faz preflight OPTIONS e GET simples com Origin fake.

lê: envia OPTIONS/GET para a URL fornecida
console · javascript
(async (url = '/api/user/me') => {
  const results = {};
  try {
    const pre = await fetch(url, { method: 'OPTIONS', headers: { Origin: 'https://evil.example', 'Access-Control-Request-Method': 'GET' } });
    results.preflight = { status: pre.status, allowOrigin: pre.headers.get('access-control-allow-origin'), allowCred: pre.headers.get('access-control-allow-credentials') };
  } catch (e) { results.preflight = { err: e.message }; }
  try {
    const r = await fetch(url, { credentials: 'include' });
    results.get = { status: r.status, cors: r.headers.get('access-control-allow-origin') };
  } catch (e) { results.get = { err: e.message }; }
  console.table(results);
  return results;
})('/api/user/me'); // troque a URL

Decodificar todo JWT do storage/cookies

auth/tokensexpõe segredo

▸ objetivo: Ver claims, exp, roles, tenant sem sair do console.

▸ o que faz: Regex acha JWTs, decoda header+payload, checa exp.

lê: localStorage/sessionStorage/cookies
console · javascript
(() => {
  const src = [
    JSON.stringify(Object.entries(localStorage)),
    JSON.stringify(Object.entries(sessionStorage)),
    document.cookie,
  ].join('\n');
  const rx = /eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{5,}/g;
  const jwts = [...new Set(src.match(rx) || [])];
  const dec = (b) => JSON.parse(atob(b.replace(/-/g, '+').replace(/_/g, '/')));
  const parsed = jwts.map(t => {
    try {
      const [h, p] = t.split('.');
      const payload = dec(p);
      return {
        head: dec(h), payload,
        exp_iso: payload.exp ? new Date(payload.exp * 1000).toISOString() : null,
        expirado: payload.exp ? Date.now() / 1000 > payload.exp : null,
        raw: t.slice(0, 40) + '…',
      };
    } catch (e) { return { erro: e.message, raw: t }; }
  });
  console.group('%c▸ JWTs (' + parsed.length + ')', 'color:#f66;font-weight:bold');
  parsed.forEach(j => console.log(j));
  console.groupEnd();
  return parsed;
})();

Testar presença de CSRF token em forms/headers

auth/tokensleitura passiva

▸ objetivo: Achar rota que aceita POST sem token anti-CSRF.

▸ o que faz: Lista forms sem token, e checa meta csrf-token / cookie samesite.

lê: document.forms · cookies · meta[name=csrf-token]
console · javascript
(() => {
  const meta = document.querySelector('meta[name="csrf-token"], meta[name="csrf"]')?.content || null;
  const cookies = Object.fromEntries(document.cookie.split(';').map(c => c.trim().split('=')));
  const susp = Object.keys(cookies).filter(k => /csrf|xsrf|token/i.test(k));
  const forms = [...document.forms].map(f => {
    const inputs = [...f.elements].map(i => i.name).filter(Boolean);
    return {
      action: f.action, method: f.method,
      hiddenToken: inputs.some(n => /csrf|token|nonce/i.test(n)),
      inputs,
    };
  });
  const out = { metaCsrf: meta, cookiesSuspeitos: susp, forms };
  console.log(out);
  return out;
})();

Session fingerprint (user, roles, tenant)

auth/tokensexpõe segredo

▸ objetivo: Achar quem é o usuário logado do ponto de vista do front.

▸ o que faz: Vasculha stores Redux/Zustand/Pinia + globais + JWT decodado.

lê: window.__REDUX_DEVTOOLS_EXTENSION__ · window.__NUXT__.state · window.__INITIAL_STATE__
console · javascript
(() => {
  const out = {};
  const grab = (o, path = '') => {
    if (!o || typeof o !== 'object') return;
    for (const k of Object.keys(o)) {
      if (/user|profile|account|me|session|role|tenant|permission/i.test(k)) {
        try { out[path + k] = JSON.parse(JSON.stringify(o[k])); } catch {}
      }
    }
  };
  grab(window, 'window.');
  grab(window.__NUXT__?.state, '__NUXT__.state.');
  grab(window.__INITIAL_STATE__, '__INITIAL_STATE__.');
  grab(window.__NEXT_DATA__?.props?.pageProps, 'nextPageProps.');
  console.group('%c▸ SESSION FINGERPRINT', 'color:#f6a;font-weight:bold');
  console.log(out);
  console.groupEnd();
  return out;
})();

Mapa de todos os formulários (action, campos, validação)

dom/formsleitura passiva

▸ objetivo: Listar attack surface de entrada de dados.

▸ o que faz: Enumera inputs, tipo, required, pattern e endpoint destino.

lê: document.forms + document.querySelectorAll('input,textarea,select')
console · javascript
(() => {
  const forms = [...document.forms].map((f, i) => ({
    idx: i, id: f.id, action: f.action, method: f.method,
    fields: [...f.elements].filter(e => e.name).map(e => ({
      name: e.name, type: e.type, required: e.required, pattern: e.pattern, maxLength: e.maxLength,
      value: e.type === 'password' ? '••••' : (e.value || '').slice(0, 40),
    })),
  }));
  console.table(forms.flatMap(f => f.fields.map(fd => ({ form: f.idx, action: f.action, ...fd }))));
  return forms;
})();

Achar elementos escondidos (display:none, hidden, off-screen)

dom/formsleitura passiva

▸ objetivo: Botão admin oculto, campo debug, feature flag renderizada.

▸ o que faz: Percorre DOM procurando itens escondidos com texto ou role interativa.

lê: document.querySelectorAll('*')
console · javascript
(() => {
  const out = [];
  for (const el of document.querySelectorAll('button,a,input,[role],form')) {
    const cs = getComputedStyle(el);
    const rect = el.getBoundingClientRect();
    const escondido =
      cs.display === 'none' ||
      cs.visibility === 'hidden' ||
      el.hidden ||
      rect.width === 0 || rect.height === 0 ||
      rect.top < -1000 || rect.left < -1000;
    if (escondido) {
      out.push({
        tag: el.tagName, id: el.id, cls: el.className?.toString?.().slice(0, 60),
        text: (el.innerText || el.value || '').slice(0, 60),
        href: el.href, name: el.name,
      });
    }
  }
  console.group('%c▸ elementos escondidos (' + out.length + ')', 'color:#a6f;font-weight:bold');
  console.table(out);
  console.groupEnd();
  return out;
})();

Gravar cliques → transformar em fluxo reproduzível

fluxo/usoleitura passiva

▸ objetivo: Documentar o passo-a-passo real que o usuário faz no site.

▸ o que faz: Registra cada click com seletor único + timestamp; window.__flow.stop() imprime.

lê: addEventListener('click')
console · javascript
(() => {
  if (window.__flow) return console.warn('já está gravando. Use __flow.stop()');
  const passos = [];
  const sel = (el) => {
    if (el.id) return '#' + el.id;
    const path = [];
    while (el && el.nodeType === 1 && path.length < 6) {
      let s = el.tagName.toLowerCase();
      if (el.className && typeof el.className === 'string') s += '.' + el.className.trim().split(/\s+/).slice(0, 2).join('.');
      const idx = [...el.parentNode.children].indexOf(el);
      s += ':nth-child(' + (idx + 1) + ')';
      path.unshift(s); el = el.parentElement;
    }
    return path.join(' > ');
  };
  const on = (e) => passos.push({
    t: Date.now(), tag: e.target.tagName, text: (e.target.innerText || '').slice(0, 40),
    sel: sel(e.target), url: location.pathname,
  });
  document.addEventListener('click', on, true);
  window.__flow = {
    steps: passos,
    stop() {
      document.removeEventListener('click', on, true);
      console.group('%c▸ FLUXO GRAVADO (' + passos.length + ' passos)', 'color:#f6f;font-weight:bold');
      console.table(passos);
      console.groupEnd();
      delete window.__flow;
      return passos;
    },
  };
  console.log('%c▸ gravando cliques. Rode __flow.stop() para parar.', 'color:#f6f;font-weight:bold');
})();

Auditar CSP, security headers e mixed content

csp/headersleitura passiva

▸ objetivo: Ver se o site tem CSP forte, HSTS, X-Frame etc.

▸ o que faz: Refaz GET da própria página e imprime os headers relevantes.

lê: fetch(location.href)
console · javascript
(async () => {
  const r = await fetch(location.href, { method: 'GET', credentials: 'include' });
  const keys = ['content-security-policy','strict-transport-security','x-frame-options','x-content-type-options','referrer-policy','permissions-policy','cross-origin-opener-policy','cross-origin-resource-policy'];
  const h = {}; keys.forEach(k => h[k] = r.headers.get(k));
  const mixed = [...document.querySelectorAll('[src],[href]')]
    .map(e => e.src || e.href)
    .filter(u => u.startsWith('http://') && location.protocol === 'https:');
  console.group('%c▸ Security headers', 'color:#0cf;font-weight:bold');
  console.table(h);
  console.groupEnd();
  if (mixed.length) console.warn('mixed content:', mixed);
  return { headers: h, mixed };
})();

Testar risco de clickjacking (iframe embed)

csp/headersleitura passiva

▸ objetivo: Ver se a página aceita ser embutida em iframe (X-Frame / CSP frame-ancestors).

▸ o que faz: Cria iframe temporário apontando pra própria URL e observa se carregou.

lê: cria iframe no próprio DOM
console · javascript
(() => new Promise((res) => {
  const f = document.createElement('iframe');
  f.style.cssText = 'position:fixed;bottom:0;right:0;width:200px;height:120px;border:2px solid #f00;z-index:99999';
  f.src = location.href;
  let ok = false;
  f.onload = () => { ok = true; };
  document.body.appendChild(f);
  setTimeout(() => {
    const veredicto = ok
      ? '⚠ site EMBUTÍVEL — possível clickjacking'
      : '✔ bloqueado (X-Frame-Options ou CSP frame-ancestors)';
    console.log('%c' + veredicto, 'color:' + (ok ? '#f33' : '#0f0') + ';font-weight:bold');
    f.remove();
    res(ok);
  }, 1500);
}));

Rastrear fluxo de checkout / pagamento

fluxo/usoleitura passiva

▸ objetivo: Ver ordem exata: create-order → 3DS → capture → success.

▸ o que faz: Sniffer filtrado para URLs com order/pay/checkout/capture/3ds.

lê: monkey-patch em fetch
console · javascript
(() => {
  const of = window.fetch;
  const passos = [];
  window.fetch = async function (...a) {
    const url = (typeof a[0] === 'string' ? a[0] : a[0].url);
    const t0 = performance.now();
    const res = await of.apply(this, a);
    if (/order|pay|checkout|capture|3ds|intent|confirm/i.test(url)) {
      const body = await res.clone().text();
      passos.push({ url, status: res.status, ms: (performance.now() - t0).toFixed(0), sample: body.slice(0, 300) });
      console.log('%c[$$$]', 'color:#ff0', res.status, url);
    }
    return res;
  };
  window.__checkout = passos;
  console.log('%c▸ rastreando fluxo de pagamento. Complete uma compra e veja window.__checkout', 'color:#ff0;font-weight:bold');
})();

Mapper completo de fluxo de pagamento (JS → JSON pra IA)

fluxo/usoexpõe segredo

▸ objetivo: Extrair estrutura COMPLETA de forms/endpoints/campos/headers/cookies/scripts de pagamento e devolver um JSON confidencial pronto pra colar num LLM e pedir análise de vulnerabilidades.

▸ o que faz: Varre <form>, inputs (incl. hidden), scripts do gateway (Stripe/PayPal/MercadoPago/PagSeguro/Adyen/Braintree/Cielo), monkey-patch em fetch/XHR filtrado por rotas de pagamento, coleta headers de resposta, cookies (nomes/flags), meta CSP, hosts 3rd-party, e monta window.__paymap com resumo + prompt de auditoria embutido.

lê: DOM (forms, inputs, scripts) · fetch/XHR de checkout · document.cookie (nomes/flags) · meta CSP · performance.getEntries (hosts)
console · javascript
(() => {
  const OUT = { site: location.origin, path: location.pathname, ts: new Date().toISOString(), forms: [], gateways: [], requests: [], cookies: [], csp: null, thirdParty: [], scripts: [], warnings: [] };

  // 1) forms + inputs (inclui hidden — costuma vazar amount/currency/orderId)
  document.querySelectorAll('form').forEach((f, i) => {
    const inputs = [...f.querySelectorAll('input,select,textarea')].map(el => ({
      name: el.name || null, id: el.id || null, type: el.type || el.tagName.toLowerCase(),
      value: el.type === 'password' ? '***' : (el.type === 'hidden' ? el.value : (el.value ? '<user>' : null)),
      required: el.required || false, pattern: el.pattern || null, maxLength: el.maxLength > 0 ? el.maxLength : null,
    }));
    const isPay = /pay|checkout|order|cart|charge|billing|card/i.test((f.action||'') + f.className + f.id + f.innerHTML.slice(0,500));
    if (isPay || inputs.some(x => /card|cvv|cvc|cpf|amount|price|total|order/i.test(x.name||''))) {
      OUT.forms.push({ idx: i, action: f.action, method: (f.method||'GET').toUpperCase(), enctype: f.enctype, autocomplete: f.autocomplete, novalidate: f.noValidate, inputs });
    }
  });

  // 2) gateways conhecidos (via scripts)
  const gwMap = { stripe: /js\.stripe\.com|stripe-v3/, paypal: /paypal\.com\/sdk|paypalobjects/, mercadopago: /mercadopago|mercadolibre/i, pagseguro: /pagseguro|uol\.com\.br\/checkout/, adyen: /adyen\.com/, braintree: /braintreegateway|braintree-web/, cielo: /cieloecommerce|cielo\.com\.br/, iugu: /iugu\.com/, ebanx: /ebanx/, square: /squareup|squarecdn/, klarna: /klarna\.com/, applepay: /apple-pay/i, googlepay: /pay\.google\.com|googlepay/i };
  const scripts = [...document.scripts].map(s => s.src).filter(Boolean);
  OUT.scripts = scripts;
  for (const [name, rx] of Object.entries(gwMap)) if (scripts.some(s => rx.test(s))) OUT.gateways.push(name);

  // 3) cookies (nomes + presença — nunca o valor)
  document.cookie.split(';').map(c => c.trim()).filter(Boolean).forEach(c => {
    const [n] = c.split('='); OUT.cookies.push({ name: n, hasValue: c.includes('=') });
  });
  OUT.warnings.push('cookies HttpOnly nao aparecem em document.cookie — cheque em DevTools > Application');

  // 4) CSP via meta (o header HTTP e mais confiavel)
  const csp = document.querySelector('meta[http-equiv="Content-Security-Policy"]');
  OUT.csp = csp ? csp.content : '(nao veio via meta — checar header HTTP)';

  // 5) hosts 3rd-party carregados
  OUT.thirdParty = [...new Set(performance.getEntriesByType('resource').map(r => { try { return new URL(r.name).host } catch { return null } }).filter(h => h && h !== location.host))].slice(0, 40);

  // 6) monkey-patch fetch + XHR filtrado por rotas de $
  const rxPay = /pay|checkout|order|cart|charge|intent|capture|3ds|billing|token|nonce|installment|coupon|discount/i;
  const _fetch = window.fetch;
  window.fetch = async function(u, o = {}) {
    const url = typeof u === 'string' ? u : u.url;
    const t0 = performance.now();
    const res = await _fetch.apply(this, arguments);
    if (rxPay.test(url)) {
      let bodySample = null;
      try { bodySample = (await res.clone().text()).slice(0, 400); } catch {}
      const reqHeaders = {}; try { new Headers(o.headers||{}).forEach((v,k)=>reqHeaders[k]=v); } catch {}
      const resHeaders = {}; res.headers.forEach((v,k)=>resHeaders[k]=v);
      OUT.requests.push({ url, method: (o.method||'GET').toUpperCase(), status: res.status, ms: +(performance.now()-t0).toFixed(0), reqHeaders, reqBody: typeof o.body === 'string' ? o.body.slice(0,400) : (o.body ? '[non-string body]' : null), resHeaders, resSample: bodySample });
      console.warn('[$PAY]', res.status, url);
    }
    return res;
  };
  const _open = XMLHttpRequest.prototype.open, _send = XMLHttpRequest.prototype.send;
  XMLHttpRequest.prototype.open = function(m,u){ this.__pm = { m, u }; return _open.apply(this, arguments); };
  XMLHttpRequest.prototype.send = function(b){
    if (this.__pm && rxPay.test(this.__pm.u)) {
      this.addEventListener('loadend', () => {
        OUT.requests.push({ url: this.__pm.u, method: this.__pm.m, status: this.status, reqBody: typeof b === 'string' ? b.slice(0,400) : null, resHeaders: this.getAllResponseHeaders(), resSample: (this.responseText||'').slice(0,400) });
        console.warn('[$XHR]', this.status, this.__pm.u);
      });
    }
    return _send.apply(this, arguments);
  };

  window.__paymap = OUT;
  window.__paymapReport = () => {
    const prompt = 'Voce eh auditor de seguranca (bug bounty AUTORIZADO). Analise o JSON abaixo, que descreve o fluxo de PAGAMENTO de ' + OUT.site + OUT.path + '. Liste em portugues:\n1) VULNERABILIDADES provaveis (IDOR, price tampering, mass assignment, race, CSRF, 3DS bypass, webhook forjado, PCI leak, JWT fraco, cookie sem HttpOnly/Secure/SameSite, CSP frouxa).\n2) EVIDENCIAS no JSON (aponte o campo/endpoint).\n3) PoC minima (curl/requests) para reproduzir em lab.\n4) CORRECAO recomendada (server-side, gateway config, headers).\nFormato: [severidade] titulo -> evidencia -> PoC -> fix.\nJSON:\n\`\`\`json\n' + JSON.stringify(OUT, null, 2) + '\n\`\`\`';
    navigator.clipboard?.writeText(prompt);
    console.log('%c✓ prompt + JSON copiados. Cole no LLM.', 'color:#0f0;font-weight:bold');
    return prompt;
  };
  console.log('%c▸ paymap ativo. Complete um checkout de teste e rode: __paymapReport()', 'color:#0ff;font-weight:bold');
  console.log('Resumo inicial:', { forms: OUT.forms.length, gateways: OUT.gateways, thirdParty: OUT.thirdParty.length });
})();

Mapper de pagamento em Python (requests + BeautifulSoup)

fluxo/usoexpõe segredo

▸ objetivo: Alternativa server-side: baixa a página de checkout, extrai forms/inputs/scripts/gateways, mapeia GraphQL, webhooks e polling assíncrono e devolve JSON + prompt de auditoria pronto pra IA. Útil quando não dá pra abrir o console (WAF, headless, CI).

▸ o que faz: Roda em Termux/Linux. Aceita URL, cookies e header Authorization (páginas autenticadas). Detecta forms de pagamento, hidden inputs (amount, currency, orderId), gateways por assinatura de script, hosts 3rd-party, headers de segurança (CSP, HSTS, X-Frame-Options, Set-Cookie flags), endpoints GraphQL + operationNames (query/mutation/subscription), webhooks/IPN/callbacks e padrões de polling assíncrono de status (setInterval, EventSource, WebSocket, endpoints /status|/poll|/pending).

lê: HTML da URL alvo · headers HTTP · Set-Cookie flags · hosts 3rd-party via <script>/<link> · conteúdo de scripts inline + scripts externos same-origin (limitado)
console · javascript
# salve como paymap.py e rode:  python paymap.py https://alvo/checkout
# deps:  pip install requests beautifulsoup4
import sys, json, re, urllib.parse as up
import requests
from bs4 import BeautifulSoup

URL    = sys.argv[1] if len(sys.argv) > 1 else input("URL alvo: ").strip()
COOKIE = input("Cookie header (enter p/ nenhum): ").strip()
AUTH   = input("Authorization header (enter p/ nenhum): ").strip()

H = {"User-Agent": "Mozilla/5.0 (audit)", "Accept": "text/html,*/*"}
if COOKIE: H["Cookie"] = COOKIE
if AUTH:   H["Authorization"] = AUTH

r = requests.get(URL, headers=H, timeout=20, allow_redirects=True)
soup = BeautifulSoup(r.text, "html.parser")

GW = {
    "stripe":      r"js\.stripe\.com|stripe-v3",
    "paypal":      r"paypal\.com/sdk|paypalobjects",
    "mercadopago": r"mercadopago|mercadolibre",
    "pagseguro":   r"pagseguro|uol\.com\.br/checkout",
    "adyen":       r"adyen\.com",
    "braintree":   r"braintreegateway|braintree-web",
    "cielo":       r"cieloecommerce|cielo\.com\.br",
    "iugu":        r"iugu\.com",
    "ebanx":       r"ebanx",
    "square":      r"squareup|squarecdn",
    "klarna":      r"klarna\.com",
    "applepay":    r"apple-pay",
    "googlepay":   r"pay\.google\.com|googlepay",
}

scripts  = [s.get("src") for s in soup.find_all("script") if s.get("src")]
gateways = [name for name, rx in GW.items() if any(re.search(rx, s or "", re.I) for s in scripts)]

forms = []
for i, f in enumerate(soup.find_all("form")):
    inputs = []
    for el in f.find_all(["input", "select", "textarea"]):
        t = (el.get("type") or el.name).lower()
        val = el.get("value")
        if t == "password": val = "***"
        elif t != "hidden" and val: val = "<user>"
        inputs.append({
            "name": el.get("name"), "id": el.get("id"), "type": t, "value": val,
            "required": el.has_attr("required"), "pattern": el.get("pattern"),
            "maxlength": el.get("maxlength"),
        })
    blob = " ".join([f.get("action") or "", " ".join(f.get("class") or []), f.get("id") or ""])
    pay_like = bool(re.search(r"pay|checkout|order|cart|charge|billing|card", blob, re.I)) \
        or any(re.search(r"card|cvv|cvc|cpf|amount|price|total|order", x["name"] or "", re.I) for x in inputs)
    if pay_like:
        forms.append({
            "idx": i, "action": up.urljoin(URL, f.get("action") or ""),
            "method": (f.get("method") or "GET").upper(),
            "enctype": f.get("enctype"), "autocomplete": f.get("autocomplete"),
            "inputs": inputs,
        })

target_host = up.urlparse(URL).netloc
third = sorted({up.urlparse(s).netloc for s in scripts if s and up.urlparse(s).netloc and up.urlparse(s).netloc != target_host})

sec_headers = {k: r.headers.get(k) for k in [
    "Content-Security-Policy", "Strict-Transport-Security", "X-Frame-Options",
    "X-Content-Type-Options", "Referrer-Policy", "Permissions-Policy",
    "Cross-Origin-Opener-Policy", "Cross-Origin-Resource-Policy",
]}

cookie_flags = []
for c in r.raw.headers.getlist("Set-Cookie") if hasattr(r.raw, "headers") else []:
    name = c.split("=", 1)[0].strip()
    cookie_flags.append({
        "name": name,
        "httpOnly": "httponly" in c.lower(),
        "secure":   "secure"   in c.lower(),
        "sameSite": (re.search(r"samesite=(\w+)", c, re.I).group(1) if re.search(r"samesite=", c, re.I) else None),
    })

# ---------- coleta corpus JS (inline + externos same-origin, com limite) ----------
inline_js = "\n".join([(s.string or "") for s in soup.find_all("script") if not s.get("src")])
ext_corpus = []
MAX_EXT = 8
MAX_BYTES = 400_000
for s in scripts[:MAX_EXT]:
    if not s: continue
    src_abs = up.urljoin(URL, s)
    if up.urlparse(src_abs).netloc != target_host:
        continue
    try:
        rj = requests.get(src_abs, headers=H, timeout=10)
        if rj.ok and len(rj.text) <= MAX_BYTES:
            ext_corpus.append((src_abs, rj.text))
    except Exception:
        pass
JS_ALL = inline_js + "\n" + "\n".join(t for _, t in ext_corpus)

# ---------- GraphQL ----------
gql_endpoints = sorted(set(re.findall(r"[\"'`]([^\"'`\s]*?/graphql[^\"'`\s]*)[\"'`]", JS_ALL, re.I)))
gql_ops = []
for m in re.finditer(r"\b(query|mutation|subscription)\s+([A-Za-z_][A-Za-z0-9_]*)", JS_ALL):
    gql_ops.append({"kind": m.group(1).lower(), "name": m.group(2)})
# dedup ops
_seen = set(); gql_ops = [o for o in gql_ops if (o["kind"], o["name"]) not in _seen and not _seen.add((o["kind"], o["name"]))]
gql_op_names = sorted(set(re.findall(r"operationName[\"']?\s*[:=]\s*[\"']([A-Za-z_][A-Za-z0-9_]*)", JS_ALL)))
gql_pay_ops = [o for o in gql_ops if re.search(r"pay|checkout|order|charge|cart|refund|capture|intent|subscri|invoice", o["name"], re.I)]

# ---------- Webhooks / IPN / callbacks ----------
WEBHOOK_RX = r"[\"'`]([^\"'`\s]*?/(?:webhook|webhooks|hooks|ipn|notify|notification|notifications|callback|callbacks|postback|listener|events)[^\"'`\s]*)[\"'`]"
webhook_urls = sorted(set(re.findall(WEBHOOK_RX, JS_ALL + " " + r.text, re.I)))
webhook_headers_hint = sorted(set(re.findall(r"[\"'`](x-[a-z0-9-]*(?:signature|hmac|hub-signature|webhook)[a-z0-9-]*)[\"'`]", JS_ALL, re.I)))

# ---------- Polling assíncrono de status ----------
poll_endpoints = sorted(set(re.findall(r"[\"'`]([^\"'`\s]*?/(?:status|poll|polling|pending|await|check|state|progress|order[-_]?status|payment[-_]?status|transaction[-_]?status)[^\"'`\s]*)[\"'`]", JS_ALL, re.I)))
uses_set_interval = bool(re.search(r"setInterval\s*\(", JS_ALL))
uses_recursive_timeout = bool(re.search(r"setTimeout\s*\([^)]*(?:poll|check|status|refresh|retry)", JS_ALL, re.I))
event_sources = sorted(set(re.findall(r"new\s+EventSource\s*\(\s*[\"'`]([^\"'`]+)[\"'`]", JS_ALL)))
websockets   = sorted(set(re.findall(r"new\s+WebSocket\s*\(\s*[\"'`]([^\"'`]+)[\"'`]", JS_ALL)))
status_state_machine = sorted(set(re.findall(r"[\"'`](pending|processing|awaiting_?payment|requires_?action|succeeded|paid|captured|authorized|failed|declined|refunded|reversed|chargeback)[\"'`]", JS_ALL, re.I)))

async_flow = {
    "graphql": {
        "endpoints": gql_endpoints,
        "operations": gql_ops[:200],
        "operationNamesFromRequests": gql_op_names,
        "paymentRelatedOperations": gql_pay_ops,
    },
    "webhooks": {
        "urlsHardcoded": webhook_urls,
        "signatureHeadersReferenced": webhook_headers_hint,
    },
    "polling": {
        "statusEndpoints": poll_endpoints,
        "setInterval": uses_set_interval,
        "recursiveSetTimeout": uses_recursive_timeout,
        "eventSource": event_sources,
        "webSocket": websockets,
        "statusStatesReferenced": status_state_machine,
    },
    "corpus": {
        "inlineScriptBytes": len(inline_js),
        "externalScriptsFetched": [u for u, _ in ext_corpus],
    },
}

OUT = {
    "url": URL, "status": r.status_code, "finalUrl": r.url,
    "gateways": gateways, "forms": forms, "thirdParty": third,
    "securityHeaders": sec_headers, "cookies": cookie_flags,
    "scripts": scripts[:50],
    "asyncFlow": async_flow,

}

PROMPT = (
    "Voce eh auditor de seguranca (bug bounty AUTORIZADO). Analise o JSON abaixo — "
    "fluxo de PAGAMENTO de " + URL + ".\n"
    "Liste em portugues:\n"
    "1) VULNERABILIDADES provaveis (price tampering em hidden inputs, IDOR em orderId, "
    "CSRF ausente, cookies sem HttpOnly/Secure/SameSite, CSP frouxa, HSTS ausente, "
    "gateway PCI mal integrado, scripts 3rd-party arriscados no checkout, GraphQL sem "
    "persisted queries / introspection aberta / mutations de pagamento sem authz, "
    "webhooks sem HMAC/replay-protection, endpoints de polling de status como oraculo "
    "de enumeracao ou IDOR, EventSource/WebSocket sem authz por canal).\n"
    "2) EVIDENCIAS (aponte o campo/endpoint/header/operationName no JSON, incluindo "
    "asyncFlow.graphql, asyncFlow.webhooks e asyncFlow.polling).\n"
    "3) PoC minima (curl) para reproduzir em lab.\n"
    "4) CORRECAO recomendada.\n"
    "Formato: [severidade] titulo -> evidencia -> PoC -> fix.\n\n"
    "JSON:\n\`\`\`json\n" + json.dumps(OUT, indent=2, ensure_ascii=False) + "\n\`\`\`\n"
)

with open("paymap.json", "w", encoding="utf-8") as fp:
    json.dump(OUT, fp, indent=2, ensure_ascii=False)
with open("paymap.prompt.txt", "w", encoding="utf-8") as fp:
    fp.write(PROMPT)

print("[ok] gerados: paymap.json + paymap.prompt.txt")
print(f"gateways: {gateways}  forms: {len(forms)}  3rd-party: {len(third)}")
print(f"graphql endpoints: {len(async_flow['graphql']['endpoints'])}  ops: {len(async_flow['graphql']['operations'])}  webhooks: {len(async_flow['webhooks']['urlsHardcoded'])}  polling: {len(async_flow['polling']['statusEndpoints'])}  ws/sse: {len(async_flow['polling']['webSocket']) + len(async_flow['polling']['eventSource'])}")

▸ combine com

  • /prompts — jogue a saída do console num LLM (Burp/Nmap/API copilots) pra sugerir próximos passos.
  • /guias/charles-windows — capture tráfego mobile e cruze com o sniffer.
  • /plans — playbooks completos que integram esses snippets como fase de recon.