# Ferramentas de segurança de agentes de processo único vs. baseadas em daemon

Um diagrama de processos pode fazer um produto de segurança parecer tranquilizadoramente simples ou impressionantemente sério. Nenhuma dessas impressões diz se um agente autônomo de programação pode usar uma credencial de forma indevida, falar com um serviço local não pretendido ou deixar uma ação sem registro depois de uma falha.

A comparação útil é concreta: conte os limites de confiança, examine as interfaces que os atravessam e acompanhe um segredo desde o armazenamento até a solicitação externa. Um único processo de aplicativo pode reduzir os componentes locais. Um daemon pode isolar privilégios ou manter um serviço ativo entre clientes. Os dois designs falham quando seus autores confundem separação de processos com autorização.

## A quantidade de processos não define o limite de segurança

Um design de processo único coloca a interface do usuário, o cofre de credenciais, o estado de aprovação, a validação de solicitações, a ação de rede e o registro no mesmo espaço de endereçamento. Não há um socket de cliente local entre suas próprias partes, nenhum registro de serviço independente para manter e nenhum protocolo usado por um processo local para comandar outro. Isso pode reduzir de forma significativa a superfície de ataque.

Também cria um grande domínio de confiança. Se um invasor obtiver execução de código dentro desse processo, poderá alcançar todos os componentes que o processo alcança. Corrupção de memória, carregamento de plugins maliciosos, atualizações inseguras ou uma interface de script ampla demais tornam-se especialmente graves porque o cofre e o executor ficam ao lado do código comum do aplicativo.

Um design baseado em daemon divide essas funções. Um aplicativo de desktop ou cliente de linha de comando envia uma solicitação a um serviço em segundo plano. O serviço pode manter os segredos e fazer a chamada de rede, enquanto o cliente mostra as aprovações e recebe os resultados. Isso pode limitar o que um cliente comprometido consegue fazer, mas somente se o daemon recusar solicitações que o cliente não tem autorização para realizar.

Essa condição costuma ser esquecida nas discussões de arquitetura. Um socket Unix restrito a uma conta de usuário é acesso ao transporte, não prova de que o chamador é o agente ou aplicativo aprovado. Todo processo executado por esse usuário pode conseguir abri-lo. Se o daemon aceita uma solicitação como «usar a credencial X com a URL Y» de qualquer peer local, uma extensão maliciosa do editor, um script de shell ou um agente comprometido pode pedir a mesma ação.

Separe estas três ideias:

- Um limite de processo separa a memória.
- Um limite de privilégio restringe o que o código pode fazer depois de um comprometimento.
- Um limite de autorização decide qual chamador pode solicitar cada ação.

As equipes frequentemente tratam a primeira como prova das outras duas. Não é. Dois processos executados pelo mesmo usuário com um canal IPC não autenticado têm heaps separados, mas ainda podem estar no mesmo domínio de autorização.

Um processo único evita um problema de autorização IPC porque suas chamadas internas não atravessam o limite de um serviço local. Isso não elimina a necessidade de identificar uma sessão externa do agente antes de aprovar uma ação. Um daemon acrescenta esse problema de identificação duas vezes: uma no endpoint do cliente e, muitas vezes, outra em qualquer endpoint administrativo que ele exponha.

## Um socket local é uma API que código hostil pode chamar

Os defensores de daemons costumam dizer, corretamente, que o serviço escuta apenas no localhost ou em um socket Unix. O que fica de fora é que o código local é justamente onde a maioria das integrações de agentes é executada. O agente de programação, o terminal, o editor, os scripts de build, os hooks de pacotes e os auxiliares do navegador compartilham a mesma máquina.

Trate um endpoint IPC local como trataria uma pequena API de rede. Defina formatos de mensagem restritos. Recuse campos desconhecidos quando o protocolo permitir. Vincule cada solicitação a uma identidade de chamador e a uma sessão de curta duração. Limite o tamanho das solicitações, a concorrência e as opções de destino. Registre as solicitações recusadas, além das bem-sucedidas, porque várias recusas podem revelar uma integração tentando contornar o caminho previsto.

No macOS, inspecione uma ferramenta antes de confiar na afirmação de que ela funciona apenas localmente:

```sh
ps -axo pid,ppid,user,command | grep -i '[a]gent\\|[d]aemon'
lsof -nP -iTCP -sTCP:LISTEN
launchctl print gui/$(id -u) 2>/dev/null | grep -i -C 2 'agent\\|vault\\|security'
```

O segundo comando normalmente mostra colunas com este formato quando um processo escuta em TCP:

```text
COMMAND   PID USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
service  4128 sam     9u  IPv4 0x...            0t0  TCP 127.0.0.1:48120 (LISTEN)
```

Nenhuma saída de `lsof` não prova que a ferramenta não usa IPC. Sockets Unix não aparecem nessa consulta TCP. Verifique os diretórios de suporte do aplicativo, os diretórios temporários e a documentação do serviço para encontrar os caminhos dos sockets. Depois, confira as permissões com `ls -l` e pergunte se outro processo pertencente à sua conta consegue se conectar.

O manual de `launchd.plist` da Apple descreve `KeepAlive` como um conjunto de condições sob as quais launchd reinicia um job. Isso é útil na operação, mas cria uma obrigação de segurança. Um serviço que reinicia precisa recuperar corretamente seu estado bloqueado, seu estado de sessão e seu estado de auditoria. «Ele volta automaticamente» não responde ao que o serviço aceita no primeiro segundo depois da reinicialização.

Um bom daemon transforma a identidade do chamador em parte do protocolo, em vez de tratá-la como uma suposição fornecida pelo cliente. O mecanismo exato depende do sistema operacional. Em plataformas que conseguem expor as credenciais do peer de um socket local, use-as. Onde houver informações de assinatura de código, verifique-as antes de conceder uma sessão. Não aceite como identidade o nome de um processo, um PID fornecido em JSON ou um caminho digitado pelo chamador. Os três podem ser falsificados ou estar desatualizados quando forem inspecionados.

## O comportamento na inicialização decide se a proteção existe quando é necessária

Um processo de aplicativo único normalmente começa quando o usuário abre o app. Seu estado sensível tem um ciclo de vida simples: o app inicia, o usuário o desbloqueia, as sessões aprovadas são executadas e fechar ou interromper o app encerra o acesso. É fácil explicar e testar esse comportamento.

O custo é a disponibilidade. Um agente de linha de comando não pode usar o gateway enquanto o aplicativo está fechado, ainda iniciando, bloqueado ou parado em um pedido de permissão do sistema. Esse pode ser exatamente o comportamento certo para um gateway de credenciais controlado por uma pessoa. É inadequado quando o trabalho precisa ser executado sem supervisão depois de uma reinicialização e o produto não tem uma forma segura de recuperar sua autoridade.

Um daemon normalmente inicia no login, sob demanda ou na inicialização do sistema. Cada escolha muda o modelo de ameaça. Um serviço iniciado no login pode esperar pelo armazenamento de chaves do usuário e pela sessão de desktop. Um serviço iniciado no boot pode funcionar antes que alguém possa aprovar qualquer coisa. Um serviço sob demanda reduz a exposição quando está ocioso, mas sua primeira solicitação não pode disputar com a inicialização.

Já vi a versão problemática dessa falha: a interface inicia devagar, o serviço em segundo plano já aceita solicitações e o serviço trata «nenhum estado de aprovação carregado» como equivalente a «nenhuma aprovação necessária». Desenvolvedores criam esse caminho para evitar um erro de inicialização. Invasores e automações instáveis não se importam com o motivo de ele existir.

Descreva a máquina de estados. Ela deve responder às perguntas abaixo sem evasivas:

1. O executor pode aceitar uma solicitação antes de o cofre informar se está bloqueado ou desbloqueado?
2. O que acontece com uma aprovação vinculada a um processo cliente quando esse processo termina?
3. O que o serviço faz depois de reiniciar enquanto uma solicitação está em andamento?
4. Um pedido de aprovação pendente pode sobreviver à reinicialização e ser associado a outro chamador?
5. Sair da conta revoga o estado utilizável das credenciais do serviço?

Para ações de alto risco, falhe de forma segura durante toda transição ambígua. Uma solicitação que chega enquanto o serviço inicializa deve receber uma recusa explícita ou uma resposta temporária de indisponibilidade. Ela não deve herdar uma aprovação antiga, uma credencial descriptografada em cache ou uma decisão padrão de permitir.

A inicialização também afeta o comportamento dos usuários. Se um fluxo de agente falha porque alguém precisa reativar manualmente um serviço oculto, as pessoas vão desabilitar a barreira ou armazenar um token em uma variável de ambiente. Controles de segurança que não resistem a suspensão, logout e reinicialização comuns ensinam os usuários a contorná-los.

## As credenciais precisam chegar ao executor sem passar pelo agente

A questão central das credenciais não é saber se uma ferramenta criptografa um cofre. É saber se o agente recebe o segredo em alguma forma que possa copiar, imprimir, colocar em um arquivo ou transmitir para outro endpoint.

A disposição mais segura mantém a credencial em um cofre controlado pelo gateway. O agente envia uma solicitação de ação. O gateway verifica o estado de autorização, injeta a credencial na solicitação HTTP externa ou na operação SSH, executa a ação e devolve o resultado. O agente recebe os dados produzidos pelo sistema remoto, não o token bearer ou a chave privada.

Essa diferença importa porque agentes trabalham com texto. Se um token aparece na saída de uma ferramenta, um modelo pode repeti-lo em um comando de shell, arquivo-fonte, descrição de issue, log de build ou transcrição de conversa. Mascarar um campo de exibição depois não corrige a exposição. O segredo já atravessou o limite.

O Secrets Management Cheat Sheet da OWASP recomenda evitar segredos embutidos no código e rotacioná-los quando houver suspeita de exposição. A recomendação está certa, mas é incompleta para fluxos de agentes. Um segredo pode ficar fora do controle de versão e ainda vazar por uma resposta de ferramenta. O gateway precisa impedir a divulgação no momento em que executa a ação.

Um daemon pode proteger bem esse limite quando controla a descriptografia e a rede externa. O cliente envia uma descrição da operação, nunca uma solicitação de material secreto bruto. O daemon também deve evitar devolver diagnósticos amplos demais. Uma resposta de autenticação malsucedida pode informar que a solicitação falhou. Não precisa devolver o cabeçalho de autorização injetado, uma configuração SSH serializada ou um despejo de memória do provedor de credenciais.

Um processo único pode seguir a mesma regra. Seu executor interno lê o cofre e faz a chamada, enquanto o agente se comunica por um ponto de integração restrito. A vantagem é que nenhum segundo processo precisa acessar material descriptografado. O risco é que recursos comuns do aplicativo possam ficar no mesmo domínio de memória que o segredo.

Evite estas disposições tentadoras:

- Colocar tokens de API em variáveis de ambiente do processo do agente.
- Escrever um arquivo de credencial temporário que um subprocesso possa ler.
- Retornar um placeholder que o cliente troca depois pelo token real.
- Permitir que um daemon local exponha um método «obter segredo» por conveniência.
- Passar bytes de uma chave privada SSH pela entrada padrão.

O padrão do placeholder merece desconfiança especial. Um placeholder só é seguro se nunca conceder acesso à credencial fora do gateway e não puder ser reutilizado por outro processo. Na prática, as equipes frequentemente o transformam em um token bearer não documentado. Então acabam criando uma segunda credencial, com controles de ciclo de vida mais fracos.

Para SSH, aplique a mesma disciplina. Um auxiliar pode precisar usar uma chave para estabelecer uma conexão, mas o agente deve pedir que ele execute um comando remoto específico ou uma operação de conexão rigorosamente limitada. Dar uma chave privada ao agente porque ele «só precisa dela por pouco tempo» continua sendo dar uma chave privada a ele.

## Mais processos criam mais manutenção, não mais maturidade

Um daemon traz trabalho operacional que um aplicativo de desktop de processo único evita. Alguém precisa instalá-lo, iniciá-lo no contexto correto de usuário ou sistema, atualizá-lo, verificar seu binário, lidar com falhas, remover registros antigos e garantir que o socket e os arquivos de log tenham o proprietário correto depois das atualizações.

Isso não é um argumento contra daemons. É um argumento contra fingir que essas tarefas desaparecem dentro do sistema operacional. `launchd` pode reiniciar um job. Não pode decidir se um novo binário mantém as verificações esperadas do chamador, se um socket antigo sobreviveu a uma atualização ou se um serviço agora inicia com um conjunto diferente de entitlements.

Um daemon também complica a compatibilidade de versões. Um shim de linha de comando pode falar o protocolo na versão A enquanto o serviço instalado espera a versão B. Se os autores lidarem mal com essa incompatibilidade, o cliente recorre a um caminho de compatibilidade não autenticado ou desabilita verificações para preservar uma experiência fluida. Código de compatibilidade causou mais problemas do que muitas equipes esperam porque é executado justamente quando o sistema é menos compreendido.

Use uma recusa explícita para versões incompatíveis. O erro deve informar ao usuário que um dos lados precisa ser atualizado, sem negociar silenciosamente um modo mais fraco. Mantenha o protocolo pequeno o suficiente para testar clientes antigos, reinicializações do serviço, mensagens malformadas e solicitações simultâneas sem precisar montar um laboratório inteiro.

Aplicativos de processo único também precisam de disciplina nas atualizações. Um aplicativo assinado pode mudar sua própria implementação e o esquema do cofre. A diferença é mais estreita: há um único ciclo de vida executável para inspecionar, e o processo que apresenta a aprovação é o mesmo que executa a ação protegida. Uma atualização ainda pode introduzir uma falha, mas não introduz automaticamente um protocolo RPC local e o estado de um gerenciador de serviços.

A diferença fica mais clara para as equipes. Um daemon central pode oferecer um endpoint local estável a várias ferramentas, reduzindo integrações duplicadas. Também pode se tornar um ponto único de falha compartilhado. Um serviço travado pode bloquear todos os fluxos de desenvolvimento na máquina. Um único serviço com permissões amplas demais pode dar a cada cliente local acesso a todas as credenciais configuradas.

Não trate um ícone de fundo na barra de menus como prova de que um daemon está saudável. Teste os casos difíceis: force o encerramento da interface, mate o serviço, reinicie durante uma sessão ativa, atualize primeiro o cliente, atualize primeiro o serviço e remova uma credencial enquanto uma solicitação aguarda aprovação. Se a resposta para algum caso for «provavelmente se recupera», você ainda não conhece o comportamento operacional.

## A aprovação pertence a uma execução identificada, não a uma máquina lembrada

Os sistemas de aprovação falham quando autorizam um conceito vago como «este computador» ou «o usuário atual». Agentes autônomos frequentemente criam processos filhos, reiniciam depois de edições e chamam ferramentas por meio de shells. Uma permissão que acompanha toda essa atividade é ampla demais para ter um significado útil.

Vincule a aprovação a uma execução específica do processo ou a outra identidade que não possa ser copiada por código local não relacionado. A tela de aprovação deve mostrar informações de origem suficientes para que uma pessoa perceba uma surpresa: a autoridade de assinatura do executável, o caminho do comando e a classe da solicitação são evidências melhores do que apenas um nome amigável de cliente. Qualquer pessoa pode escolher um nome de processo.

Depois, torne a duração explícita. Uma aprovação para uma sessão curta de agente pode ser razoável para chamadas repetidas de baixo risco. Credenciais sensíveis podem exigir consentimento a cada uso. A revogação deve interromper imediatamente a execução identificada, em vez de apenas escondê-la de um painel enquanto sua conexão local continua aberta.

Um daemon tem uma obrigação adicional. Ele precisa associar uma conexão IPC à identidade aprovada pela pessoa e descartar essa associação quando o cliente termina ou se reconecta. Nunca permita que um cliente retome uma sessão antiga apenas apresentando um identificador em cache. Se o identificador pode viajar por um arquivo ou argumento de comando, ele é uma credencial bearer com um nome sofisticado.

Um design de processo único pode manter o estado de aprovação ao lado da integração ativa, reduzindo o trabalho de associação. Ainda precisa distinguir uma inicialização do agente de outra. Se o aplicativo não consegue saber se uma solicitação veio da execução aprovada ou de um processo substituto iniciado depois, deve pedir aprovação novamente.

A política útil costuma ser mais simples do que as equipes imaginam: recusar enquanto o cofre está bloqueado, perguntar uma vez para uma execução recém-identificada e exigir confirmação individual para credenciais que justificam esse atrito. Linguagens locais de política muito elaboradas frequentemente criam regras que ninguém consegue auditar sob pressão. Um caminho curto de decisão, que os usuários conseguem prever, é mais fácil de testar e mais difícil de contornar por acidente.

## Uma falha na reinicialização expõe o ponto fraco

Considere uma pessoa desenvolvedora que aprovou um agente de programação para fazer chamadas HTTP comuns durante uma execução ativa no terminal. O gateway mantém a aprovação na memória. O agente envia uma solicitação e o gateway começa a preparar a chamada externa. Nesse momento, a interface falha ou o executor em segundo plano reinicia depois de uma atualização.

Uma implementação descuidada de daemon pode piorar a situação de várias formas. O executor volta antes de carregar o estado de bloqueio do cofre. O socket do cliente reaparece no mesmo caminho. O agente se reconecta. O daemon vê um identificador de sessão em cache na solicitação e presume que a aprovação antiga continua válida. Enquanto isso, o gravador de auditoria ainda não reabriu o log, então a nova tentativa bem-sucedida fica sem um registro durável.

Cada decisão isolada parece conveniente: preservar uma sessão, reduzir pedidos de aprovação, reiniciar rapidamente e armazenar logs em buffer. Juntas, elas criam uma ação não aprovada justamente no período em que o sistema tem o estado menos confiável.

O comportamento seguro é mais simples. Depois de reiniciar, descarte as aprovações voláteis. Mantenha o cofre indisponível até conhecer seu estado de proteção. Recuse novas ações até que o gravador de auditoria esteja pronto para confirmar um registro. O agente deve receber uma recusa ou uma resposta temporária de indisponibilidade e, depois, exigir uma nova aprovação se a sessão não existir mais.

Você pode testar isso sem hardware especial:

1. Abra uma nova sessão de agente e aprove uma solicitação permitida de baixo impacto.
2. Inicie outra solicitação que aguarde em um ponto de aprovação ou endpoint de teste.
3. Encerre o processo ou serviço de segurança enquanto a solicitação aguarda.
4. Reinicie-o e tente novamente a solicitação a partir do processo original do agente.
5. Verifique se uma nova autorização é necessária e se o resultado final aparece uma única vez no registro de auditoria.

Repita o teste com uma reconexão do cliente, um bloqueio do dispositivo, uma credencial removida e uma atualização. Procure autoridade antiga, execução duplicada ou registros ausentes. Uma ferramenta que não consegue tornar esses resultados visíveis é difícil de confiar durante um incidente.

## Os registros de auditoria precisam de um gravador que não possa ser contornado

Os logs de segurança frequentemente registram o que a interface viu, não o que o executor de credenciais fez. Essa lacuna se torna grave quando um daemon aceita solicitações locais diretamente. Um cliente comprometido pode ignorar a interface, ou a interface pode falhar depois que o executor age.

Coloque a gravação de auditoria no caminho da ação. O componente que envia a solicitação HTTP ou chama o auxiliar SSH deve registrar a identidade do chamador, a referência da credencial, o destino, a classe da solicitação, a decisão e o resultado. Não registre segredos brutos nem corpos por padrão. Logs que contêm tokens bearer se tornam outro cofre, com controle de acesso pior.

Um processo único pode tornar essa ordem direta: validar, registrar a decisão, executar e registrar o resultado. Um daemon precisa garantir que seu próprio executor não consiga realizar uma solicitação por um canal alternativo que evite o componente de registro. Separe o registro da execução por IPC somente quando puder aceitar o modo de falha e provar a ordem dos eventos.

A evidência de adulteração importa depois de um comprometimento, não apenas durante a solução de problemas. Se um invasor pode editar um arquivo SQLite local ou apagar linhas específicas de um log de texto, o registro pode ajudar na depuração, mas não estabelece um histórico confiável. Um registro orientado a anexação com encadeamento criptográfico permite detectar alterações, desde que os arquivos necessários sejam preservados e verificados.

O Sallyport mantém as visualizações de sessões e chamadas projetadas a partir de um único log de auditoria criptografado e encadeado por hash, e seu comando `sp audit verify` verifica a cadeia offline sem precisar de uma chave do cofre. Esse design resolve um problema criado com frequência por logs separados da interface e do daemon: dois registros que discordam sobre a ocorrência de uma ação.

Não exagere o que a auditoria pode fazer. Uma cadeia não recupera um evento que um invasor impediu o programa de registrar. Ela pode detectar alterações no conjunto de registros que recebeu. Isso ainda é útil, especialmente quando uma falha, uma atualização ou um cliente local inesperado obriga você a reconstruir uma sequência depois do ocorrido.

## Escolha o design menor que atenda ao ciclo de vida necessário

Escolha um processo único quando o trabalho protegido exige a presença de uma pessoa, o aplicativo pode permanecer aberto enquanto os agentes executam suas tarefas e reduzir endpoints locais é mais útil do que sobreviver de forma independente da interface. Esse modelo combina com um gateway de credenciais cuja principal promessa é permitir que uma pessoa veja e controle cada execução do agente.

Escolha um daemon quando o trabalho realmente precisa de continuidade do serviço, separação de um cliente menos confiável ou um privilégio distinto do sistema operacional. Exija uma resposta para cada interface adicionada: quem se conecta, como o serviço identifica essa pessoa ou processo, qual solicitação pode fazer, quando o estado expira e o que acontece quando qualquer um dos lados reinicia.

Uma ferramenta de desktop como o Sallyport segue o caminho do processo único e usa um shim MCP comum para as solicitações dos agentes. Seu cofre executa a ação HTTP ou SSH por conta própria, para que o agente nunca receba a credencial de API ou SSH configurada.

Antes de adotar qualquer modelo, faça uma verificação sem ilusões. Mate o componente que detém a autoridade enquanto um agente trabalha, reinicie-o e confira se a próxima solicitação é recusada, aprovada novamente e registrada. Esse teste revela mais sobre o design do que qualquer diagrama de arquitetura bem elaborado.
