Skip to main content
Como os webhooks funcionam
Language

Webhooks

Configure destinos de webhook para receber alertas de segurança do cside via requisições HTTP POST com verificação de assinatura HMAC.

Como os webhooks funcionam

Os webhooks permitem que você receba notificações do cside como requisições HTTP POST para uma URL que você especificar. Quando um trigger dispara, o cside envia um payload JSON para o seu endpoint de webhook contendo detalhes sobre o evento.

Você pode configurar webhooks em três formatos:

  • JSON - payload JSON padrão para integrações personalizadas
  • Slack - pré-formatado para canais Slack
  • Discord - pré-formatado para canais Discord

Para criar itens de trabalho do Jira a partir de webhooks em qualquer plano, consulte Jira Automation.

Adicionando um destino de webhook

Para adicionar um webhook como destino em uma notification config:

  1. Abra o painel e navegue até Team Settings > Notifications
  2. Crie uma nova notification config ou edite uma existente
  3. Em Send To, clique em Add destination e selecione Webhook
  4. No painel de Configuration, preencha:
    • URL: a URL onde você deseja receber as notificações de webhook (ex.: https://example.com/cside/notify)
    • Secret: uma chave secreta usada para assinar as requisições de webhook (usada para verificação HMAC)
    • Format: escolha JSON, Slack ou Discord
  5. Clique em Save ou Save & Test

O cside assina cada requisição com o header x-cside-signature, mas não consegue adicionar headers personalizados. Se o seu receptor autentica com um header próprio, verifique se ele também aceita o token na URL, como faz o Jira Automation.

O payload do webhook

O cside envia uma requisição HTTP POST por evento, com Content-Type: application/json e um header x-cside-signature (consulte Verificação HMAC). Cada payload traz um campo event de nível superior que identifica o tipo do evento, um timestamp, a equipe ou o domínio ao qual o evento pertence e um objeto data específico do evento.

O campo que contém o timestamp varia por evento: alert.created e os eventos de digest usam timestamp, enquanto security_headers.changed usa sent_at. Leia event primeiro e depois interprete o restante do payload de acordo com as tabelas abaixo. Trate campos desconhecidos como opcionais para que novos campos não quebrem a sua integração.

Todo payload JSON também traz dois campos legíveis por humanos, summary (um título de uma linha) e description (detalhes em várias linhas), presentes no nível superior e repetidos dentro de data. Use-os para preencher um ticket ou uma mensagem de chat sem precisar montar o seu próprio texto para cada evento. Eles são repetidos dentro de data porque o Jira Automation trata de forma especial uma chave data de nível superior.

Event IDs

IDEnviado porCampo de timestampObjeto data
alert.createdTriggers imediatos e o trigger Vulnerable Script Detected na programação imediatatimestampObjeto de alerta
security_headers.changedSecurity Headers Changedsent_atMudança de cabeçalhos de segurança
pci_report.availablePCI Report (diário ou semanal)timestampRelatório PCI
csp_block_digestScript Blocked by CSP (diário ou semanal)timestampDigest de bloqueios de CSP
csp_policy_digestCSP Policy Digest (diário ou semanal)timestampDigest de política de CSP
vulnerable_script_digestVulnerable Script Detected (diário ou semanal)timestampDigest de vulnerabilidades
outbound_connections_pending_reviewOutbound Connections Pending Review (diário ou semanal)timestampConexões de saída pendentes

Somente alert.created, security_headers.changed e pci_report.available respeitam os formatos Slack e Discord. Os outros eventos de digest são sempre enviados como JSON, independentemente do formato configurado no destino.

Save & Test envia um payload alert.created de exemplo com o trigger_type do trigger da regra, inclusive para triggers que normalmente entregam um digest. O summary desse payload começa com [Test]. Security Headers Changed envia, em vez disso, um payload security_headers.changed de exemplo. Se o seu endpoint responder com um erro, o resultado do teste mostra o código de status HTTP que ele retornou.

Todos os timestamps são strings ISO 8601 em UTC. Os IDs são strings decimais.

alert.created

Enviado para cada alerta gerado por um trigger imediato: Script Threat Detected, High-risk Vulnerability, Managed Flagged, Malicious Tag Manager, Malicious Outbound Connection e Vulnerable Script Detected quando a regra está configurada para entrega imediata.

CampoTipoDescrição
event"alert.created"O ID do evento
timestampstringQuando o webhook foi enviado
domain_idstringID do domínio em que o alerta disparou
domainstringNome de host do domínio em que o alerta disparou
trigger_typestringO trigger que gerou o alerta, veja a tabela abaixo
summarystringTítulo de uma linha, por exemplo [cside] Malicious Script: {ruleset} on {domain}. O mesmo texto que a integração do Jira usa no campo Summary da issue
descriptionstringExplicação do alerta em texto simples
dataobjectO objeto de alerta
destination_idstringID do destino de webhook que recebeu o evento

Valores de trigger_type:

trigger_typeTrigger
script_threat_detected_by_rules_engineScript Threat Detected
high_risk_vulnerability_detectedHigh-risk Vulnerability
vulnerable_script_detectedVulnerable Script Detected (programação imediata)
cside_managed_list_flaggedManaged Flagged
malicious_tag_managerMalicious Tag Manager
malicious_outbound_connectionMalicious Outbound Connection

Objeto de alerta

CampoTipoDescrição
summarystringO mesmo que o summary de nível superior
descriptionstringO mesmo que o description de nível superior
domainstringO mesmo que o domain de nível superior
trigger_typestringO mesmo que o trigger_type de nível superior
target_type"URL" | "HASH" | "IP" | "DOMAIN" | "HOSTNAME" | "VENDOR"O que target contém
targetstringO objeto do alerta: a URL de um script, o hash de um script, ou o IP, domínio ou nome de host sinalizado
action"alert"A ação registrada para o alerta. Atualmente sempre "alert"; trate-a como uma string para manter a compatibilidade com ações futuras
ruleset_idstringID do ruleset que correspondeu
ruleset_namestringNome do ruleset que correspondeu
ruleset_descriptionstringDescrição do ruleset que correspondeu
script_urlsstring[]As URLs de script que dispararam o alerta; pode estar vazio
vuln_cve_idstring | nullID da vulnerabilidade (CVE ou GHSA); null para alertas que não são de vulnerabilidade
vuln_packagestring | nullPacote afetado; null para alertas que não são de vulnerabilidade
vuln_severitystring | nullSeveridade reportada, como HIGH; null para alertas que não são de vulnerabilidade
vuln_reference_urlstring | nullLink para a vulnerabilidade no osv.dev; null quando não há vuln_cve_id

Os quatro campos vuln_* só são preenchidos para vulnerable_script_detected e high_risk_vulnerability_detected. Para qualquer outro trigger_type, eles são null.

{
  "event": "alert.created",
  "timestamp": "2026-09-17T10:15:30.123456Z",
  "domain_id": "1897425263682514945",
  "domain": "checkout.example.com",
  "trigger_type": "high_risk_vulnerability_detected",
  "summary": "[cside] High-risk Vulnerability: CVE-2024-1234 on checkout.example.com",
  "description": "cside detected a high-risk vulnerability on checkout.example.com: lodash. Severity: High.\n\nThis is a high-risk finding (malware or a high-severity vulnerability). Investigate it promptly: if it is malware, remove the script immediately and rotate any credentials it may have accessed; otherwise prioritize updating or removing the affected dependency.",
  "data": {
    "summary": "[cside] High-risk Vulnerability: CVE-2024-1234 on checkout.example.com",
    "description": "cside detected a high-risk vulnerability on checkout.example.com: lodash. Severity: High.\n\nThis is a high-risk finding (malware or a high-severity vulnerability). Investigate it promptly: if it is malware, remove the script immediately and rotate any credentials it may have accessed; otherwise prioritize updating or removing the affected dependency.",
    "domain": "checkout.example.com",
    "trigger_type": "high_risk_vulnerability_detected",
    "target_type": "URL",
    "target": "https://cdn.example.com/lodash.js",
    "action": "alert",
    "ruleset_id": "ruleset_vulnerability_detected",
    "ruleset_name": "Vulnerability Detected",
    "ruleset_description": "A script with a known vulnerability was loaded",
    "script_urls": ["https://cdn.example.com/lodash.js"],
    "vuln_cve_id": "CVE-2024-1234",
    "vuln_package": "lodash",
    "vuln_severity": "HIGH",
    "vuln_reference_url": "https://osv.dev/vulnerability/CVE-2024-1234"
  },
  "destination_id": "1897425263682514950"
}

security_headers.changed

Enviado por Security Headers Changed quando os cabeçalhos de segurança observados nas páginas de checkout de um domínio diferem entre duas janelas de observação consecutivas.

CampoTipoDescrição
event"security_headers.changed"O ID do evento
sent_atstringQuando o webhook foi enviado
team_idstringID da equipe proprietária do domínio
summarystring[cside] Security headers changed on {domain}
descriptionstringUma linha por cabeçalho alterado: - {header}: {from} -> {to}
data.summarystringO mesmo que summary
data.descriptionstringO mesmo que description
data.domain_idstringID do domínio
data.domainstringNome de host do domínio
data.checkout_pathsstring[]Os seletores de página de checkout que foram observados
data.changesobject[]Uma entrada por cabeçalho alterado
data.changes[].header_namestringO cabeçalho, por exemplo content-security-policy
data.changes[].from_valuestringO valor anterior; vazio quando o cabeçalho foi adicionado
data.changes[].to_valuestringO novo valor; vazio quando o cabeçalho desapareceu
data.changes[].from_datestringInício da janela de observação em que o valor anterior foi visto
data.changes[].to_datestringInício da janela de observação em que o novo valor foi visto

pci_report.available

Enviado por PCI Report assim que o relatório do período fica pronto, para os domínios no escopo que têm caminhos de checkout configurados. Ele é enviado uma vez por relatório; uma entrega rejeitada não é reenviada. Cada requisição também traz um header x-cside-delivery-id que permanece o mesmo se o mesmo relatório for entregue novamente, para que você possa deduplicar com base nele.

CampoTipoDescrição
event"pci_report.available"O ID do evento
timestampstringQuando o webhook foi enviado
organization_idstringID da organização
team_idstringID da equipe
summarystring[cside / PCI DSS]: New PCI Compliance Report for {domains} (os três primeiros domínios, depois “and N more”)
descriptionstringUma frase que cita os domínios e as datas, seguida do link do relatório
data.summarystringO mesmo que summary
data.descriptionstringO mesmo que description
data.report_idstringID do relatório
data.report_urlstringLink para baixar o relatório no painel do cside
data.domain_idsstring[]IDs dos domínios cobertos pelo relatório
data.domainsstring[]Nomes de host dos domínios cobertos pelo relatório, na mesma ordem
data.starting_datestringInício do período do relatório
data.ending_datestringFim do período do relatório
data.period"daily" | "weekly" | "custom"A duração do período do relatório. custom é usado para um relatório que cobre qualquer outro intervalo

csp_block_digest

Enviado por Script Blocked by CSP com os relatórios de violação da Content Security Policy coletados no período. Nada é enviado quando não houve violações.

CampoTipoDescrição
event"csp_block_digest"O ID do evento
timestampstringQuando o webhook foi enviado
organization_idstringID da organização
team_idstringID da equipe
summarystringTítulo de uma linha para o digest
descriptionstringDetalhamento do digest em várias linhas
data.summarystringO mesmo que summary
data.descriptionstringO mesmo que description
data.period"daily" | "weekly"A programação da regra
data.start_datestringInício do período do digest
data.end_datestringFim do período do digest
data.domainsobject[]Contagens por domínio, ordenadas pelo número de violações
data.domains[].domain_idstringID do domínio
data.domains[].domainstringNome de host do domínio
data.domains[].violation_countnumberViolações registradas para o domínio
data.top_blocked_urisstring[]As URIs bloqueadas com mais frequência
data.top_violated_directivesstring[]As diretivas violadas com mais frequência
data.total_violationsnumberTotal de violações em todos os domínios no escopo

csp_policy_digest

Enviado por CSP Policy Digest para cada domínio no escopo cuja Content Security Policy recomendada mudou no período. Nada é enviado quando nenhum domínio mudou.

CampoTipoDescrição
event"csp_policy_digest"O ID do evento
timestampstringQuando o webhook foi enviado
organization_idstringID da organização
team_idstringID da equipe
summarystringTítulo de uma linha para o digest
descriptionstringDetalhamento do digest em várias linhas
data.summarystringO mesmo que summary
data.descriptionstringO mesmo que description
data.period"daily" | "weekly"A programação da regra
data.domainsobject[]Uma entrada por domínio cuja política mudou
data.domains[].domainstringNome de host do domínio
data.domains[].domain_idstringID do domínio
data.domains[].addedstring[]Hosts adicionados à política recomendada
data.domains[].removedstring[]Hosts removidos da política recomendada
data.domains[].flaggedstring[]Hosts removidos que estão na lista gerenciada de ameaças do cside
data.domains[].host_countnumberNúmero de hosts na política recomendada
data.domains[].policy_headerstringO valor completo recomendado do header Content-Security-Policy

vulnerable_script_digest

Enviado por Vulnerable Script Detected em uma programação diária ou semanal com as descobertas de vulnerabilidade rotineiras (não de alto risco) do período. Nada é enviado quando não houve descobertas.

CampoTipoDescrição
event"vulnerable_script_digest"O ID do evento
timestampstringQuando o webhook foi enviado
organization_idstringID da organização
team_idstringID da equipe
summarystringTítulo de uma linha para o digest
descriptionstringDetalhamento do digest em várias linhas
data.summarystringO mesmo que summary
data.descriptionstringO mesmo que description
data.period"daily" | "weekly"A programação da regra
data.start_datestringInício do período do digest
data.end_datestringFim do período do digest
data.domainsobject[]Contagens por domínio
data.domains[].domain_idstringID do domínio
data.domains[].domainstringNome de host do domínio
data.domains[].vulnerability_countnumberDescobertas registradas para o domínio
data.top_vulnerabilitiesobject[]As descobertas mais frequentes
data.top_vulnerabilities[].vulnerability_idstringID da vulnerabilidade (CVE ou GHSA)
data.top_vulnerabilities[].packagestringPacote afetado
data.top_vulnerabilities[].severitystringSeveridade reportada
data.top_vulnerabilities[].occurrence_countnumberQuantas vezes a descoberta ocorreu
data.total_vulnerabilitiesnumberTotal de descobertas em todos os domínios no escopo

outbound_connections_pending_review

Enviado por Outbound Connections Pending Review com o número de nomes de host de saída que a sua equipe ainda não aprovou no inventário de Resources. Nada é enviado quando não há nada pendente.

CampoTipoDescrição
event"outbound_connections_pending_review"O ID do evento
timestampstringQuando o webhook foi enviado
organization_idstringID da organização
team_idstringID da equipe
summarystringTítulo de uma linha para o digest
descriptionstringDetalhamento do digest em várias linhas
data.summarystringO mesmo que summary
data.descriptionstringO mesmo que description
data.period"daily" | "weekly"A programação da regra
data.pending_hostname_countnumberNomes de host de saída distintos aguardando revisão
data.domain_countnumberNúmero de domínios no escopo em que eles foram observados

Verificação HMAC

Toda requisição de webhook inclui um header x-cside-signature contendo um hash HMAC SHA256 do corpo da requisição, assinado com o secret que você forneceu ao criar o destino de webhook.

Você deve sempre verificar essa assinatura para confirmar que a requisição veio do cside e prevenir ataques de replay.

Como verificar a assinatura

Se você está usando JavaScript, use nosso pacote JavaScript para verificação integrada.

Para outras linguagens, calcule o hash HMAC SHA256 do corpo bruto da requisição usando seu secret de webhook e compare-o com o valor do header x-cside-signature.

async function verifyHmac(body: string, signature: string, secret: string) {
	const encoder = new TextEncoder();
	const encodedBody = encoder.encode(body);

	const key = await crypto.subtle.importKey(
		"raw",
		encoder.encode(secret),
		{ name: "HMAC", hash: "SHA-256" },
		false,
		["sign"]
	);

	const signatureBuffer = await crypto.subtle.sign("HMAC", key, encodedBody);

	const finalSig = Array.from(new Uint8Array(signatureBuffer))
		.map((byte) => byte.toString(16).padStart(2, "0"))
		.join("");

	return signature.toLowerCase() === finalSig;
}
fn verify_hmac(body: &str, signature: &str, secret: &str) -> Result<(), &'static str> {
      let mut mac = HmacSha256::new_from_slice(secret.as_bytes()).map_err(|_| "Invalid secret")?;
      mac.update(body.as_bytes());
      let result = mac.finalize();
      let code_bytes = result.into_bytes();
      let final_sig = hex::encode(code_bytes);

      if signature.to_lowercase() == final_sig {
          Ok(())
      } else {
          Err("Invalid signature")
      }
  }

  // Add to Cargo.toml:
  // [dependencies]
  // hmac = "0.12"
  // sha2 = "0.10"
  // hex = "0.4"
package main

import (
  "crypto/hmac"
  "crypto/sha256"
  "encoding/hex"
  "strings"
)

func verifyHmac(body, signature, secret string) bool {
	h := hmac.New(sha256.New, []byte(secret))
	h.Write([]byte(body))
	finalSig := hex.EncodeToString(h.Sum(nil))

	return strings.ToLower(signature) == finalSig
}
defmodule HmacVerifier do
	def verify_hmac(body, signature, secret) do
		final_sig =
			:crypto.mac(:hmac, :sha256, secret, body)
			|> Base.encode16(case: :lower)

			String.downcase(signature) == final_sig
	end
end
import hmac
import hashlib
import secrets

def verify_hmac(body: str, signature: str, secret: str) -> bool:
	final_sig = hmac.new(
		secret.encode('utf-8'),
		body.encode('utf-8'),
		hashlib.sha256
	).hexdigest()

	return signature.lower() == final_sig
Was this page helpful?