Dados sensíveis em relatórios de crash: pare os vazamentos de contexto dos agentes
Dados sensíveis em relatórios de crash podem expor prompts de agentes, corpos de requisições e tokens. Saiba como reduzir a coleta, testar exportações e manter diagnósticos com segurança.

Os relatórios de crash podem se tornar silenciosamente o maior caminho de exportação de dados em uma aplicação com agentes. As equipes protegem as credenciais de produção, mas deixam um SDK de exceções coletar breadcrumbs, contexto HTTP, detalhes do processo e entradas de ferramentas copiadas antes de enviar o pacote para a conta de um fornecedor. O crash aconteceu localmente. As evidências não ficaram locais.
A solução não é abandonar os relatórios de crash. Você precisa deles quando uma integração com agentes falha de um jeito que os logs comuns não conseguem explicar. O trabalho consiste em decidir quais informações de depuração podem sair da máquina, parar de coletar material bruto das requisições por padrão e provar que o coletor respeita esses limites. Já vi análises de incidentes saírem dos trilhos porque o stack trace era inofensivo, mas um campo de contexto «útil» continha a requisição inteira que havia falhado.
Relatórios de crash são pacotes de evidências, não apenas stack traces
Um relatório de crash costuma ser um pacote montado em várias camadas. O sistema operacional pode criar um relatório de diagnóstico nativo. A aplicação pode anexar metadados da exceção. Um SDK de crash pode incluir dados do dispositivo, breadcrumbs, histórico da sessão, logs, campos de tracing e tags definidas pelo usuário. Um framework de agentes pode já ter serializado o prompt, a entrada da ferramenta, a resposta ou o estado da nova tentativa em um desses campos.
Essa diferença importa porque os desenvolvedores tendem a auditar o stack trace visível e considerar o resultado limpo. O material sensível costuma estar ao lado dele.
Um relatório pode expor dados por meio de:
- mensagens de exceção que inserem uma URL, um comando ou o corpo de uma resposta
- breadcrumbs criados a partir de logs de requisições ou eventos de chamadas de ferramentas
- campos personalizados que recebem um objeto de requisição inteiro
- argumentos de linha de comando, caminhos de arquivos temporários e valores derivados do ambiente
- arquivos anexados, screenshots, reprodução de sessão ou feedback de suporte
Um endereço de memória em um relatório nativo normalmente não revela uma chave de API por si só. Já uma string copiada para uma mensagem de panic pode revelar. Não misture esses dois casos. Diagnósticos nativos precisam de controles de acesso; a telemetria da aplicação precisa de uma redução deliberada dos dados.
A documentação da Apple sobre relatórios de diagnóstico os descreve como registros usados para diagnosticar problemas em aplicações, com informações sobre processos e threads. Isso é útil e normalmente mais restrito que um evento de monitoramento da aplicação. Porém, quando um SDK enriquece esse relatório com o contexto do seu próprio runtime, a fronteira dos dados muda. Trate o evento enriquecido como dado da aplicação a caminho de outro sistema.
Falhas de agentes criam um contexto de diagnóstico especialmente rico
Um handler de requisição comum pode falhar com uma rota e um código de status. Uma ação de agente pode carregar uma instrução do usuário, caminhos de repositórios, saída de comandos, argumentos para uma API remota, um destino SSH e os resultados anteriores das ferramentas que levaram à falha. Esse contexto ajuda a reproduzir o bug. Também torna a coleta descuidada muito mais cara.
O caminho de risco é previsível. Um desenvolvedor envolve cada chamada de ferramenta em um logger conveniente. O logger emite o objeto completo de argumentos. O SDK de observabilidade converte os registros em breadcrumbs. Um timeout de rede dispara uma exceção. Agora o relatório contém a entrada da ferramenta, incluindo cabeçalhos ou um token colado, e o fornecedor a recebe.
A mesma falha aparece quando o código faz isto:
try {
await runTool(toolName, input);
} catch (error) {
throw new Error(`Tool failed: ${toolName} input=${JSON.stringify(input)} error=${error.message}`);
}
Essa mensagem parece útil durante um teste local. Em produção, ela cria um campo de dados sem limite que todo coletor de erros, destino de logs e integração de alertas pode copiar. Substitua-a por identificadores estáveis e um resumo baseado em uma lista permitida:
try {
await runTool(toolName, input);
} catch (error) {
throw new Error(`Tool failed: name=${toolName} request_id=${requestId} input_shape=${inputShape}`);
}
inputShape pode significar uma lista de nomes e tamanhos de campos aprovados, nunca os valores dos campos. Se você não consegue explicar por que um campo pertence a um evento de erro, deixe-o de fora. A reprodução deve começar com um ID de correlação que aponte para um registro local protegido, não com uma requisição completa colada em um painel hospedado.
A captura bruta de requisições é um padrão ruim
A captura bruta de requisições continua popular porque torna a primeira sessão de depuração rápida. Ela é inadequada como padrão para serviços que lidam com ações de agentes. Cabeçalhos de autorização, cookies, URLs assinadas, parâmetros de consulta, corpos de requisição e cabeçalhos personalizados costumam conter material que não deveria estar em um sistema de crashes.
Um evento seguro tem informações suficientes para agrupar, fazer a triagem e encaminhar o incidente:
{
"request_id": "rq_8c2f1a",
"channel": "http",
"method": "POST",
"route": "/v1/issues/{issue_id}/comments",
"status_class": "5xx",
"duration_ms": 8120,
"attempt": 2,
"error_kind": "upstream_timeout"
}
A rota usa um modelo, não o caminho literal. O evento informa que a requisição foi repetida, não o que ela enviou. O ID opaco permite que um responsável autorizado consulte o registro local de origem se precisar.
Não faça hash de segredos e chame isso de redação. Um hash determinístico ainda pode identificar um bearer token repetido e ser vulnerável quando o valor original tem um espaço de busca pequeno. Substitua valores sensíveis por um marcador constante ou omita-os. Se você precisa saber se havia uma credencial, registre auth_present: true, não seu tipo, tamanho, prefixo ou impressão digital.
Revise também o tratamento de URLs. Muitas bibliotecas registram URLs completas automaticamente. Uma rota como /callback?code=... ou uma URL de download assinada pode vazar por um campo que o desenvolvedor nunca adicionou manualmente. Remova as strings de consulta antes que o evento entre no SDK, em vez de esperar que um processador posterior reconheça todas as variações.
A redação precisa acontecer antes do armazenamento e da exportação
Um scrubber é uma proteção adicional, não uma autorização para coletar tudo. Os hooks dos SDKs variam: alguns processam o evento final, alguns processam apenas campos selecionados e outros não abrangem anexos de crash nativo ou breadcrumbs produzidos por uma integração separada. Uma regra que remove Authorization pode não detectar authorization, x-api-token, um parâmetro de URL ou uma string JSON inserida em uma exceção.
Construa a fronteira em camadas. Primeiro, desative a captura automática de que você não precisa. Depois, monte os eventos a partir de campos permitidos. Em seguida, execute um scrubber defensivo sobre todas as strings restantes. Por fim, teste os dados serializados recebidos pelo coletor.
Este pseudocódigo mostra a ordem que evita a maioria dos problemas:
request arrives
-> derive route template and request ID
-> retain protected local diagnostic record if policy permits
-> create minimal crash context from allowlisted fields
-> scrub all residual strings
-> send minimized event
Não passe o objeto de requisição original para um callback «before send». Quando uma biblioteca inspeciona esse objeto, plugins podem já tê-lo transformado em breadcrumbs ou spans. Entregue ao código de telemetria um objeto pequeno que não possa conter campos sensíveis desde o início.
A Sentry documenta a limpeza de dados e os processadores de eventos, enquanto o Firebase Crashlytics documenta chaves personalizadas e coleta de logs. Leia essas configurações como controles de coleta, não como uma garantia genérica de privacidade. Nos dois casos, o contexto personalizado e os logs são os pontos em que as equipes de aplicação mais costumam anular suas próprias proteções padrão.
Os padrões do SDK mudam quando as integrações mudam
Uma atualização do SDK de crash pode adicionar tracing, captura do console, breadcrumbs, reprodução de sessão, instrumentação de desempenho ou uma integração de framework que enxerga mais do estado da requisição. Uma análise de segurança feita quando o aplicativo tinha apenas stack traces não cobre esse novo caminho de dados.
Mantenha um inventário pequeno da coleta para cada runtime. Registre o coletor de crashes nativo, o SDK de exceções, a ponte de logs, o pacote de tracing, o widget de feedback e o mecanismo de pacote de suporte. Para cada um, responda a quatro perguntas simples: o que dispara a coleta, quais campos são coletados automaticamente, onde os dados ficam armazenados antes do envio e quem pode lê-los depois do envio.
Não se esqueça dos canais indiretos. Os desenvolvedores costumam desativar os corpos de requisição no produto de crashes, mas encaminham a mesma exceção para um agregador de logs. As regras de alerta podem copiar o texto da exceção para notificações no chat. Um botão de suporte pode anexar um arquivo local de logs. Você precisa de um único mapa de dados para o caminho do incidente, não de uma história otimista separada para cada fornecedor.
No macOS, inspecione os relatórios da aplicação e os diagnósticos do sistema operacional. Os relatórios de crash da Apple podem permanecer locais ou ser compartilhados conforme as opções de relatório do sistema, enquanto os SDKs de terceiros seguem sua própria configuração e caminho de rede. Um aplicativo para desktop deve deixar essa diferença clara para as pessoas que o operam. «Os relatórios de crash estão desativados» não significa nada se um cliente separado de monitoramento de erros ainda envia eventos enriquecidos.
Mantenha as credenciais fora do processo do agente
A redação reduz a exposição depois que o código já lidou com um segredo. A medida mais forte é impedir que o processo do agente tenha o segredo. Assim, um crash do agente, uma cópia do ambiente e um dump de depuração acidental terão menos material sensível disponível para captura.
Isso não torna um relatório de crash inofensivo. O agente ainda pode conter código privado, prompts ou argumentos de ferramentas. Mas um bearer token não pode vazar de um processo que nunca o recebeu.
A Sallyport segue essa fronteira para APIs HTTP e ações SSH: o aplicativo mantém as credenciais em seu cofre criptografado, executa a ação e devolve o resultado ao agente, sem entregar o material das credenciais. Isso elimina um modo recorrente de falha na telemetria de crashes, mas você ainda precisa reduzir os dados das requisições e o texto dos resultados processados pelo agente.
Evite também colocar segredos nos argumentos de comandos. Os argumentos de processos aparecem em ferramentas de diagnóstico com mais frequência do que os desenvolvedores imaginam, e o histórico do shell ou a inspeção de processos podem expô-los independentemente dos relatórios de crash. Passe o material secreto por um broker protegido ou por um mecanismo local cuidadosamente gerenciado, não por um argumento visível como --token=....
A retenção local também precisa de uma regra
Manter relatórios completos na máquina pode ser adequado para falhas difíceis, especialmente durante um desenvolvimento controlado. Isso não é automaticamente seguro. Um spool local pode sobreviver ao incidente, ser copiado para um arquivo de suporte ou permanecer em um perfil de usuário compartilhado onde outro processo possa lê-lo.
Separe dois registros. Envie um evento remoto reduzido para agrupamento e alertas. Mantenha qualquer registro de reprodução mais completo localmente, em um local protegido, por um período curto de retenção e com um caminho explícito de exclusão. O evento remoto precisa do ID opaco do registro local, não do seu conteúdo.
Um registro local útil inclui o identificador exato do build, uma impressão digital de configuração sanitizada, o horário e uma referência à tentativa de ação. Ele não deve ser um arquivo de texto solto que concatena variáveis de ambiente, corpos de requisição e saída do terminal. O armazenamento estruturado local permite aplicar as mesmas regras de lista permitida e exclusão usadas nas exportações.
Para gateways de ações de agentes, os registros de auditoria exigem atenção especial. Eles ajudam a estabelecer o que o agente tentou fazer, mas não autorizam espelhar credenciais brutas ou prompts inteiros em todos os subsistemas de diagnóstico. O registro de auditoria da Sallyport separa os registros de ações do próprio agente, e o comando sp audit verify verifica offline a cadeia de hashes criptografada sem uma chave do cofre. A verificação informa se o histórico foi alterado; a redução de dados ainda decide qual contexto de diagnóstico pertence a outros lugares.
Prove o coletor com segredos plantados
A revisão da configuração encontra erros óbvios. Um teste com dados plantados encontra os erros que realmente importam. Execute-o antes do lançamento, depois de atualizações dos SDKs de telemetria e sempre que um framework de agentes ganhar uma nova ferramenta ou integração de logs.
Use strings marcadoras únicas que não possam ser confundidas com credenciais reais. Coloque marcadores diferentes nos lugares que as equipes costumam esquecer: um cabeçalho de autorização, um parâmetro de consulta, um campo do corpo JSON, uma instrução do agente, uma variável de ambiente, um argumento de comando e um resultado de ferramenta. Dispare uma exceção controlada e depois pesquise em todos os destinos.
Verifique a visualização do evento no fornecedor, a exportação bruta do evento quando disponível, o spool local de crashes, os logs da aplicação, os eventos de tracing, os payloads de alertas, os anexos de suporte e qualquer fila entre a aplicação e o coletor. Procure os marcadores exatos e transformações comuns, como codificação de URL ou JSON escapado. Inspecionar apenas o painel web é uma forma de deixar passar um vazamento em um breadcrumb ou log anexado.
Registre o resultado esperado. Por exemplo, um relatório pode conter route=/v1/files/{file_id} e request_id=rq_test_01, mas não pode conter MARKER_HEADER_7, MARKER_PROMPT_7 nem a string de consulta literal. Trate um teste com falha como um defeito de segurança: desative o caminho de captura problemático, adicione um teste de regressão e teste novamente o evento serializado.
Uma revisão pequena detecta a maioria das exportações acidentais
Revise a telemetria de crashes sempre que alguém alterar o tratamento de erros, a observabilidade, uma ferramenta do agente ou os diagnósticos de suporte. O revisor deve perguntar se o novo código pode serializar um objeto no formato de uma requisição, não apenas se adicionou um novo campo secreto.
Use esta lista curta durante a revisão:
- As mensagens de erro contêm identificadores e categorias, não entradas ou saídas serializadas.
- A telemetria recebe contexto permitido, nunca uma requisição bruta ou um objeto de estado do agente.
- As URLs perdem as strings de consulta e os cabeçalhos nunca entram em breadcrumbs ou campos personalizados.
- Os diagnósticos locais completos têm armazenamento protegido, regras de exclusão e um motivo definido para existir.
- Um teste com marcadores plantados cobre todos os destinos de exportação configurados.
A parte incômoda é que bons hábitos de depuração costumam causar o vazamento. Os desenvolvedores adicionam contexto porque o último incidente não tinha informações suficientes. Mantenha o contexto que classifica a falha, preserve evidências mais completas sob controle local quando houver justificativa e pare de exportar material bruto só porque um SDK de crash oferece um campo para isso.
FAQ
Relatórios de crash podem conter chaves de API ou prompts de agentes?
Sim. Um relatório de crash pode incluir argumentos do processo, caminhos derivados do ambiente, módulos carregados, pilhas de threads, breadcrumbs, logs e o estado da aplicação capturado pouco antes da falha. A presença de um segredo depende do que o programa colocou na memória, nos logs, nas URLs, nas mensagens de exceção ou nos metadados.
É seguro enviar relatórios de crash de produção para um serviço de terceiros?
A coleta de crashes só é suficientemente segura depois que você trata o processo como um destino externo de dados e testa o payload real do evento. As garantias do fornecedor não eliminam um token inserido em uma URL, um corpo de requisição registrado como breadcrumb ou um prompt copiado para uma mensagem de exceção.
Devo incluir cabeçalhos HTTP nos relatórios de crash?
A maioria das equipes deve manter os cabeçalhos de requisição fora da telemetria de crashes. Se o relatório precisar de contexto da requisição, envie o método permitido, o modelo da rota, a classe do status e um ID de correlação, em vez do mapa bruto de cabeçalhos.
Posso confiar em um recurso de limpeza do sistema de relatórios de crash para remover segredos?
Uma função de redação ajuda, mas não consegue limpar dados que o SDK capturou antes de ela ser executada nem dados expostos por outra integração. Primeiro desative a coleta arriscada, depois use a redação como proteção adicional e teste-a continuamente.
Que dados os sistemas de relatório de crash coletam por padrão?
Sistemas de crash para dispositivos móveis e desktops costumam coletar por padrão informações do dispositivo, a versão do aplicativo, frames da pilha e metadados de diagnóstico. Logs, chaves personalizadas, screenshots, reprodução de sessão, breadcrumbs e feedback do usuário normalmente exigem uma análise separada, porque podem carregar muito mais contexto.
Quais informações da requisição são úteis sem vazar a própria requisição?
Capture o modelo da rota, o método HTTP, a classe da resposta, o tempo decorrido, o número de tentativas e um ID opaco da requisição. Não capture query strings, corpos, cabeçalhos de autorização, cookies ou os argumentos completos das ferramentas do agente, a menos que um fluxo local analisado especificamente exija isso.
Como testar se a telemetria de crashes vaza segredos?
Use um crash sintético ou uma exceção controlada em um projeto que não seja de produção. Depois, inspecione o evento no console do fornecedor, o JSON exportado, o spool local e qualquer sistema de logs conectado. Procure strings marcadoras inseridas nos cabeçalhos, parâmetros de consulta, texto do prompt e variáveis de ambiente.
As chamadas de ferramentas de agentes podem aparecer no monitoramento de erros?
Um sistema de crashes pode capturar argumentos indiretamente se a biblioteca cliente registrar a entrada da ferramenta como breadcrumb, log, atributo de span, campo de contexto personalizado ou texto de exceção. Trate prompts de agentes e payloads de ferramentas como dados sensíveis da aplicação, mesmo quando não são credenciais.
Variáveis de ambiente vazam por meio de relatórios de crash?
Desative a captura automática do ambiente quando o SDK permitir e nunca coloque segredos em nomes de variáveis de ambiente ou argumentos de linha de comando. Mais importante, retire as credenciais do processo do agente para que um pacote de diagnóstico acidental tenha menos dados para expor.
Os relatórios de crash devem permanecer na máquina local?
Mantenha artefatos brutos de diagnóstico em uma máquina local com acesso controlado ou envie apenas um evento reduzido ao coletor hospedado. Se precisar enviar artefatos mais completos para depuração, use um fluxo de incidente separado, com limites de retenção e aprovadores definidos, em vez de tornar a captura completa o padrão.