JustCyber Scan
Ver o que o seu domínio mostra para a internet — depois de provar que ele é seu.
O Scan varre a superfície externa de um domínio que o cliente comprovou ser dele. O fluxo é fixo e não tem atalho: registra o ativo, publica um registro TXT no DNS com o token que a API devolve, o backend consulta o TXT e só então o ativo vira `verified`. Sem ativo verificado não existe varredura — `create_job` recusa com `scan.asset_not_verified`. E nem o alvo nem a flag de autorização vêm do corpo do request: são derivados do ativo já verificado. É a diferença entre um scanner e um proxy de ataque.
A varredura é passiva e roda fora do request. O job nasce `queued`, o evento `scan.job.requested` sai pelo outbox na mesma transação, o relay o entrega na fila isolada `scanning` e o worker revalida a propriedade do ativo antes de qualquer pacote. As checagens são as que um navegador faria: seis cabeçalhos de segurança na raiz (HSTS, CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy), certificado e protocolo TLS na 443 (expirado, expirando em menos de 15 dias, autoassinado, hostname divergente, TLS abaixo de 1.2), SPF/DMARC/CAA no DNS, e a presença de quatro caminhos óbvios (/.env, /.git/config, /server-status, /.well-known/security.txt). Nada de fuzzing, brute-force, port scan ou exploração.
O guard de SSRF é a primeira coisa que roda e não é configurável. O host é resolvido uma vez, todos os IPs são checados contra as faixas privadas, loopback, link-local, CGNAT e metadata (IPv4 e IPv6, incluindo 169.254.169.254), a conexão é pinada ao IP validado — o que fecha DNS rebinding — e cada salto de redirect revalida o destino. Alvo interno derruba o job com `error='ssrf_blocked'` sem um byte sair. Os achados sobem por fingerprint estável sha256(asset_id|category|location), então re-rodar o mesmo job não duplica linha; tudo com severidade a partir de low é promovido ao Vuln Tracker do Portal, que continua sendo a única tela curada.
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.
-
Propriedade provada antes de varrer
Registro do ativo, geração de token, instrução com nome e valor exatos do TXT, e consulta DNS real para decidir verified/failed. O token é reusado enquanto pendente (não quebra a publicação que o cliente já fez) e só rotaciona se o ativo estava failed.
-
Varredura passiva executada em worker isolado
Cabeçalhos HTTP, TLS/certificado, DNS (SPF/DMARC/CAA) e exposição de quatro caminhos óbvios. Cada checagem é resiliente: uma falha isolada não derruba as demais, e o budget total encerra a varredura no tempo.
-
Guard de SSRF com pinagem de IP
Resolução única, validação de todos os IPs, conexão pinada ao IP validado com SNI do hostname real, revalidação a cada redirect. Alvo não-roteável encerra o job como failed antes de qualquer pacote.
-
Achados deduplicados e promovidos
UPSERT por (tenant_id, scan_job_id, fingerprint) com first_seen/last_seen, e promoção idempotente de severidade >= low para portal_vulnerabilities com source='scan'.
-
Triagem do achado pelo cliente
PATCH move o achado entre open, accepted (risco aceito), resolved e false_positive, com before/after no audit_log.
-
Enriquecimento por IA sob demanda
O VulnScan AI explica o achado em PT-BR, prioriza (p1..p4) e sugere remediação ancorado na evidência já coletada — sem nova saída de rede ao alvo. Cobrado por enrich com hold-then-capture: enrich que falha não é cobrado. O resultado é gravado em evidence->'ai' e já sai nos GET de findings.
-
Ingestão de achados do navegador
Uma extensão Chrome MV3 autenticada por API key de máquina abre sessão contra um ativo verified e envia o que o navegador do próprio operador já carregou. Achado cujo host observado diverge do ativo é rejeitado, não gravado. Evidência é redigida (segredos, tokens, PEM e JWT mascarados) antes de persistir.
-
Reaper de jobs presos
Beat periódico ceifa jobs `running` mais velhos que o timeout configurado — worker morto no meio não deixa job pendurado para sempre.
Entregáveis
- Tela /app/scan com ativos, instrução de verificação DNS, varreduras e achados, consumindo o backend real
- Instrução de verificação com o nome e o valor exatos do registro TXT a publicar
- Lista de achados com severidade, categoria, título, evidência e histórico first_seen/last_seen
- Vulnerabilidades promovidas ao Vuln Tracker do Portal (portal_vulnerabilities, source='scan')
- Trilha append-only em audit_log de cada passo: ativo registrado, verificação iniciada, verificada/falhou, job pedido, job falhou, achado triado
O que este módulo não faz
Os quatro níveis de scan (basic/intermediate/advanced/ultra) são rótulo, não profundidade: o PassiveEngine chama run_passive_checks(job.target) sem repassar o nível, e a função não tem parâmetro para ele — pedir 'ultra' executa exatamente as mesmas checagens e o mesmo budget de 'basic'. A própria UI marca os três níveis acima de basic como indisponíveis. Só passivo: sem exploração, fuzzing, brute-force, port scan ou teste autenticado; as portas consultadas são 80 e 443 por padrão. O motor alternativo `opencode` (agente de recon) existe no código mas nasce fail-closed — sem JC_OPENCODE_SERVER_URL e senha ele levanta EngineUnavailable e o job falha; o default é `passive`. Não há varredura agendada ou recorrente por ativo: o único beat do Scan é o reaper de jobs presos, toda varredura é disparada por chamada. Achados enviados pela extensão são gravados e aparecem em GET /scan/findings, mas o evento scan.client.findings.received NÃO tem consumidor no relay do outbox — a priorização por IA e a promoção automática ao Vuln Tracker que a docstring do módulo promete para origin='client_side' não acontecem hoje. A prova de propriedade é só por DNS TXT (não há arquivo HTTP nem meta tag).
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
- outbox transacional + Celery (fila isolada `scanning`)
- Vuln Tracker do Portal (portal_vulnerabilities)
- VulnScan AI (app/vulnscan) para o enrich por IA
- CyberScore (reusa run_passive_checks com include_exposure=False)
- Estúdio de Casos (dedup_key estável no outbox evita re-cobrança)
- Extensão Chrome MV3 (app/apps/extension) via API key de máquina
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.
- scan:asset:read
- scan:asset:write
- scan:job:read
- scan:job:write
- scan:finding:read
- scan:finding:write
- scan:client:read
- scan:client:write
Quer ver funcionando?
Demonstração com dado do seu ambiente, não com base de exemplo. É a única forma de saber se serve.