Documentação

Monitoramento e alertas de mudanças

O AppSafe compara cada escaneamento de um site verificado com o anterior e informa o que mudou. Com escaneamentos agendados ou reescaneamento no deploy, isso vira um monitoramento contínuo com alertas por e-mail, Slack, Discord ou um webhook assinado.

Os alertas de mudanças estão incluídos nos planos Pro, Agency e Team. Os escaneamentos agendados rodam diária ou semanalmente no Pro e no Agency, e a cada hora no Team.

O que o AppSafe compara

Os alertas são enviados nos escaneamentos agendados e no deploy, uma vez por problema: um problema que continua igual não gera um novo alerta no próximo escaneamento. Se ele sumir e voltar, você será alertado de novo.

Configure os alertas

Abra um site verificado no seu painel e adicione canais em Monitoramento e alertas. Cada canal tem uma severidade mínima e um botão Enviar alerta de teste.

Payload do webhook

Webhooks genéricos recebem este JSON (Content-Type: application/json). Os alertas de teste usam o evento monitoring.test e têm scan definido como null.

{
  "event": "monitoring.changes",
  "deliveryId": "5f2c9a0e41b7d3a8c6e1f0b2",
  "createdAt": "2026-10-26T12:00:00.000Z",
  "site": {
    "domain": "myapp.com"
  },
  "scan": {
    "id": "3f1c2b9e-1111-4222-8333-944455556666",
    "grade": "C",
    "score": 67,
    "reportUrl": "https://appsafe.dev/report/…"
  },
  "summary": "2 changes on myapp.com",
  "changes": [
    {
      "type": "header_removed",
      "severity": "high",
      "subject": "content-security-policy",
      "message": "content-security-policy header removed"
    },
    {
      "type": "finding_new",
      "severity": "critical",
      "subject": "baas-supabase-table-readable",
      "title": "Supabase tables readable without logging in",
      "message": "New issue: Supabase tables readable without logging in"
    }
  ]
}

Tipos de mudança: finding_new, finding_resolved, header_added, header_removed, header_weakened, header_changed, tls_changed, tls_expiring (com days), script_domain_new, sri_missing, subdomain_new, subdomain_dangling, dns_changed. Severidades: low, medium, high, critical. Os alertas incluem apenas regressões, então finding_resolved e header_added aparecem no painel e no relatório, mas não disparam alertas sozinhos.

Verifique a assinatura

Toda requisição de webhook tem um cabeçalho X-AppSafe-Signature. Calcule um HMAC-SHA256 com o segredo do seu canal sobre o timestamp, um ponto e o corpo bruto da requisição, e compare com v1 em tempo constante. Rejeite requisições cujo timestamp tenha mais de 5 minutos.

X-AppSafe-Signature: t=<unix seconds>,v1=<hex HMAC-SHA256 of "<t>.<raw body>">
X-AppSafe-Event: monitoring.changes | monitoring.test
import { createHmac, timingSafeEqual } from "node:crypto";

// header: the X-AppSafe-Signature value, e.g. "t=1761480000,v1=5d41…"
// body:   the raw request body (string), before JSON.parse
export function verifyAppSafeSignature(secret, header, body) {
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  const timestamp = Number(parts.t);
  if (!parts.v1 || Math.abs(Date.now() / 1000 - timestamp) > 300) return false;
  const expected = createHmac("sha256", secret).update(`${timestamp}.${body}`).digest();
  const given = Buffer.from(parts.v1, "hex");
  return given.length === expected.length && timingSafeEqual(given, expected);
}

O AppSafe envia cada alerta uma única vez e não tenta de novo. Responda com um status 2xx em até 8 segundos. O painel mostra o último erro de envio do canal.

O que os alertas nunca contêm

Os payloads dos alertas contêm tipos de mudança, severidades, títulos de achados, nomes de cabeçalhos, hostnames de scripts e subdomínios, e um link para o relatório. Eles nunca contêm detalhes dos achados, segredos (nem mesmo mascarados) ou dados pessoais.