ShadowSignal
Alguém registrou um domínio parecido com o seu e você só vai descobrir quando o cliente reclamar.
ShadowSignal monitora uma watchlist de ativos do próprio cliente e transforma sinal público em achado triável. O alvo nunca vem do corpo da requisição: vem sempre de um item que o tenant cadastrou. Isso não é detalhe de implementação, é a garantia de que o produto não vira ferramenta de vigilância sobre terceiros.
O que funciona hoje de ponta a ponta é o BrandSignal. Ele gera, de forma determinística, o conjunto de domínios-sósia do apex do cliente — omissão, repetição e transposição de caractere, vizinho de teclado QWERTY, hífen interno, homóglifos ASCII (rn no lugar de m, 0 no lugar de o) e troca de TLD sobre uma lista fixa de sete. Depois resolve cada variante. Variante que não resolve é descartada, para não inflar a tela com registro inexistente. A que resolve leva um GET passivo e uma consulta de MX: domínio ativo com MX publicado é o cenário de phishing por e-mail e recebe o maior risco que a fonte permite — 45 de 100, banda média. O teto vem do peso da fonte: typosquat é risco potencial, não consumado. Quem quiser tratar um ativo com mais rigor sobe o piso de severidade dele na watchlist.
O trabalho pesado roda no worker, em fila isolada. A coleta manual reserva crédito e emite o evento na mesma transação; a agendada é coberta pela assinatura e não reserva nada; um reaper ceifa run preso por worker morto e libera o crédito. Achado novo com severidade acima do piso vira e-mail. Re-observação do mesmo sinal atualiza `last_seen_at` e não realerta. Todo trecho cru passa por redação de segredo e por neutralização de cerca antes de tocar o banco.
Capacidades em operação
Cada item corresponde a funcionalidade que existe no código e é alcançável por um usuário com o escopo correto.
-
Watchlist do tenant
CRUD completo com UNIQUE por (tipo, valor) devolvendo 409, rótulo livre, liga/desliga por item e piso de severidade por ativo. Tipos aceitos: domain, brand, email, cpf_cnpj, keyword, ip.
-
BrandSignal — domínios-sósia
Geração determinística de até 40 variantes por ativo, resolução A concorrente com semáforo, GET passivo SSRF-safe e checagem de MX. Severidade derivada do risco calculado (0-100 = peso da fonte × recência × confiança): ativo com MX 45/média, ativo 38/baixa, só registrado 23/baixa. O piso de severidade do ativo na watchlist pode elevar qualquer um dos três. Evidência traz variante, técnica, IPs, servidor e presença de MX. Evidência traz variante, técnica, IPs, servidor e presença de MX.
-
Correlação positiva obrigatória
Um sinal só vira achado se casar com um ativo da watchlist do próprio tenant — apex real para BrandSignal, casamento exato do indicador para LeakSignal. Sem busca livre e sem correlação por substring frouxa.
-
Deduplicação por fingerprint
Upsert com ON CONFLICT por (tenant, watchlist, fingerprint): reobservação atualiza recência, risco, severidade e evidência sem criar achado novo e sem disparar alerta de novo.
-
RiskSignal agregado
Score 0-100 calculado na leitura por noisy-OR saturante sobre até mil achados, com retorno decrescente. Achado descartado fica fora da conta. Devolve banda, contagem por severidade, contagem por status e principais contribuintes — sem trecho sensível.
-
Triagem com máquina de estados
new leva a reviewed, confirmed ou dismissed; reviewed leva a confirmed ou dismissed; confirmed e dismissed são terminais. Transição inválida devolve erro de validação, não passa calado.
-
Coleta manual e vigilância agendada
POST /shadowsignal/collect responde 202 com o run, reserva crédito e emite o evento na mesma transação. O beat agendado enfileira coleta sem hold, com teto de runs por tick. O reaper marca run preso como falho e devolve o crédito reservado.
-
Alerta por e-mail
Achado NOVO com severidade igual ou acima do piso emite `shadowsignal.alert` no outbox, e o relay entrega à fila de e-mail; o payload só carrega ids e referências. Atenção ao default: o piso é `alta` e o BrandSignal não passa de `média` — na configuração de fábrica nenhum e-mail sai. Para receber alerta é preciso subir o piso de severidade do ativo na watchlist (o que eleva o achado) ou baixar `JC_SHADOWSIGNAL_ALERT_MIN_SEVERITY` para `medium`.
-
Higiene do dado de terceiro
`excerpt` limitado a 256 caracteres e sempre redigido (mascara credencial, PEM, JWT, variável de ambiente). Valores de string da evidência passam por neutralização de delimitador antes do INSERT.
Entregáveis
- SignalBoard em /app/shadowsignal: watchlist, achados com risco e severidade, histórico de execuções e o RiskSignal do tenant.
- E-mail de alerta para achado novo acima do piso de severidade.
- Histórico de runs com estatística por fonte e por severidade, contagem de novos achados e de alertas, e erros por coletor.
- Trilha em audit_log de pedido, conclusão e falha de coleta.
O que este módulo não faz
DarkSignal não acessa dark web, onion nem Telegram. `collect_darksignal` devolve lista vazia por construção e o run registra o módulo como `darkweb:stub_not_accessed`. LeakSignal nasce sem fonte: `JC_SHADOWSIGNAL_LEAK_INDEX_URLS` e `JC_SHADOWSIGNAL_LEAK_RANGE_URL` têm default vazio, e sem eles a etapa é pulada e devolve vazio; o feed licenciado (SpyCloud, Flare) é gancho documentado, sem código de consumo. Na configuração padrão, portanto, o único coletor que produz achado é o BrandSignal. Só os tipos `domain` e `email` têm coletor: `brand`, `keyword`, `cpf_cnpj` e `ip` podem ser cadastrados na watchlist e não são coletados. As variantes de domínio são só ASCII sobre uma lista fixa de sete TLDs — não há IDN, punycode nem homóglifo unicode. O beat de vigilância contínua só roda com `JC_SHADOWSIGNAL_ENABLED=true`, que é false por padrão.
Declaramos o limite porque software de segurança que promete tudo não é auditável. Se o que falta aqui é o que você precisa, o serviço consultivo cobre — ou dizemos que não cobre.
Conecta com
- app/cyberintel/collectors (resolvedor DNS e fingerprint HTTP reusados)
- app/scan/passive (guard SSRF e redação de segredo)
- app/core/outbox e worker Celery (fila isolada de coleta, beat e reaper)
- app/billing (hold/capture/release)
- app/worker/tasks/email (alerta)
- tela /app/shadowsignal no app web
Controle de acesso
O acesso é concedido por escopo, não por perfil genérico. Quem só precisa ler não recebe permissão de escrita, e a barreira é o banco de dados, não a interface.
- shadowsignal:watchlist:read
- shadowsignal:watchlist:write
- shadowsignal:findings:read
- shadowsignal:findings:write
- shadowsignal:collect:run
Quer ver funcionando?
Demonstração com dado do seu ambiente, não com base de exemplo. É a única forma de saber se serve.