Docs

Surveillance et alertes de changement

AppSafe compare chaque scan d’un site vérifié au précédent et vous indique ce qui a changé. Avec les scans planifiés ou le re-scan au déploiement, cela devient une surveillance continue avec des alertes par e-mail, Slack, Discord ou webhook signé.

Les alertes de changement sont incluses dans les plans Pro, Agency et Team. Les scans planifiés s’exécutent chaque jour ou chaque semaine sur Pro et Agency, et toutes les heures sur Team.

Ce qu’AppSafe compare

Les alertes sont envoyées pour les scans planifiés et les scans au déploiement, une seule fois par problème : un problème qui reste identique ne déclenche pas de nouvelle alerte au scan suivant. S’il disparaît puis revient, vous serez de nouveau alerté.

Configurer les alertes

Ouvrez un site vérifié dans votre tableau de bord et ajoutez des canaux dans Surveillance et alertes. Chaque canal a une gravité minimale et un bouton Envoyer une alerte de test.

Payload du webhook

Les webhooks génériques reçoivent ce JSON (Content-Type: application/json). Les alertes de test utilisent l’événement monitoring.test et ont scan à 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"
    }
  ]
}

Types de changement : finding_new, finding_resolved, header_added, header_removed, header_weakened, header_changed, tls_changed, tls_expiring (avec days), script_domain_new, sri_missing, subdomain_new, subdomain_dangling, dns_changed. Gravités : low, medium, high, critical. Les alertes ne contiennent que les régressions : finding_resolved et header_added apparaissent dans le tableau de bord et le rapport, mais ne déclenchent pas d’alerte à eux seuls.

Vérifier la signature

Chaque requête webhook comporte un en-tête X-AppSafe-Signature. Calculez un HMAC-SHA256 avec le secret de votre canal sur le timestamp, un point et le corps brut de la requête, puis comparez-le à v1 en temps constant. Rejetez les requêtes dont le timestamp date de plus de 5 minutes.

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);
}

AppSafe envoie chaque alerte une seule fois, sans nouvelle tentative. Répondez avec un statut 2xx en moins de 8 secondes. Le tableau de bord affiche la dernière erreur d’envoi du canal.

Ce que les alertes ne contiennent jamais

Les payloads d’alerte contiennent les types de changement, les gravités, les titres des problèmes, les noms d’en-têtes, les noms d’hôte des scripts et sous-domaines, et un lien vers le rapport. Ils ne contiennent jamais le détail des problèmes, de secrets (même masqués) ni de données personnelles.