Um mapa de falhas correto torna concreta a atribuição de responsabilidade. O modelo gerou texto, mas foi o backend que decidiu se a chamada POST /v1/tools/refund.create seria executada; é no backend que podemos comprovar o escopo do principal (entidade solicitante), exigir aprovação para ações irreversíveis e anexar uma chave de idempotência para evitar transações duplicadas em tentativas de reexecução. Ao estabelecer esse limite, tentativas de prompt injection passam a ser entradas que falham na validação e na autorização, em vez de instruções que resultam em movimentação financeira.
Pressupomos um conhecimento prático de códigos de status HTTP; ou seja, já sabemos o que uma resposta de recusa representa na comunicação de rede.
Pressupomos conhecimentos básicos de JWT, o que significa saber verificar assinaturas e validar o emissor (issuer), o público-alvo (audience) e a data de expiração utilizando uma biblioteca confiável.
Pressupomos o uso de injeção de dependência no FastAPI, permitindo implementar verificações de autenticação, autorização e cotas como dependências de escopo de requisição, em vez de espalhar essas verificações pelos handlers.
O artefato que construiremos ao longo do curso é um pipeline de backend de referência, no qual cada etapa possui um ponto claro de recusa, cada registro de log contém campos estáveis que facilitam a análise e cada caso de teste de regressão está vinculado a um controle específico. O objetivo não é criar um prompt engenhoso. O objetivo é um backend capaz de realizar RAG (Retrieval-Augmented Generation) com segurança sobre o histórico da conta, chamar refund.create apenas quando o usuário u_123 tiver permissão e aprovação, e executar scripts de análise sem conceder acesso à rede ou a segredos. O diagrama a seguir ilustra o fluxo da requisição que iremos proteger e robustecer etapa por etapa.
O backend de um copiloto de suporte baseado em FastAPI geralmente falha de maneira comum. O backend lê o histórico da conta acct_987, um modelo sugere os próximos passos e uma chamada de ferramenta emite um reembolso para a transação txn_456 porque o texto do ticket de suporte parecia convincente. Nada de incomum aconteceu. A aplicação aceitou texto não confiável do ticket, tratou a sugestão como autorização e executou refund.create com os privilégios do serviço, em vez de aplicar as permissões do usuário final e uma etapa de aprovação.
O trabalho de segurança neste curso consiste em construir as etapas de controle ausentes nos únicos locais onde elas podem ser efetivamente aplicadas. A redação do prompt não consegue impedir que um roteador de ferramentas envie uma solicitação, e um modelo não consegue provar que u_123 tem permissão para reembolsar txn_456. Ou o backend recusa a solicitação antes de a ferramenta ser executada, ou ele executa a ferramenta e gasta dinheiro real.
Mantemos uma referência concreta em todas as lições para que cada controle incida sobre os mesmos componentes. O tenant é t_acme, o usuário final é u_123, a conta é acct_987 e a transação candidata a reembolso é txn_456. A única ferramenta de reembolso chama-se refund.create, e a única rota que a acessa é POST /v1/tools/refund.create.
Também definimos o único nome de escopo que permite um reembolso. Um principal que não possua support:refund ainda pode conversar sobre políticas, resumir o histórico da conta e redigir uma resposta, mas não pode executar refund.create. A escolha do modelo permanece explícita, porém abstrata. A aplicação chama um modelo de chat por meio de $CHAT_MODEL e utiliza $MODERATION_MODEL nos casos em que uma lição posterior exigir uma chamada dedicada de triagem.
Uma vez definidos os nomes, podemos mapear um caminho único de solicitação e marcar onde dados não confiáveis entram no sistema. A mensagem do solicitante não é confiável, mesmo quando proveniente de um agente de suporte autenticado, pois pode conter texto copiado do cliente ou o conteúdo do ticket. Trechos recuperados do histórico da conta não são confiáveis, pois a recuperação retorna o que estiver armazenado, incluindo anotações desatualizadas e texto livre que pode tentar direcionar o comportamento do modelo. Resultados de ferramentas não são confiáveis, pois sistemas subsequentes podem retornar strings ou campos inesperados; da mesma forma, a saída do modelo não é confiável, pois ele é otimizado para gerar texto plausível, e não para garantir a conformidade com políticas.
O processo implementa apenas os pontos de controle capazes de transformar essas entradas não confiáveis em uma ação delimitada e auditável. Autenticamos e vinculamos uma identidade (principal) de modo que cada solicitação carregue t_acme e u_123 como fatos verificados pelo servidor, e não como cabeçalhos fornecidos pelo solicitante. Monitoramos o consumo de cotas antes da chamada ao provedor, evitando que um único endpoint esgote, da noite para o dia, a cota de tokens prevista para um mês. Autorizamos a recuperação de dados no ponto de chamada, garantindo que o backend recupere apenas fragmentos que u_123 tenha permissão para visualizar, tratando, ainda assim, cada fragmento recuperado como conteúdo não confiável. Validamos a saída estruturada do modelo antes que ela seja processada por qualquer roteador, analisador (parser), template ou ferramenta. Autorizamos e aprovamos chamadas de ferramentas para impedir que refund.create seja executada apenas porque o modelo emitiu uma sugestão persuasiva. Executamos scripts de análise em ambiente isolado (sandbox) para impedir que o código gerado acesse a rede ou segredos. Auditamos todas as recusas e ações executadas, registrando campos suficientes para explicar quem realizou a ação, para qual tenant e por que o backend a permitiu.
Quando o texto de um ticket de suporte tenta acionar um reembolso, qual etapa poderia ter recusado esse reembolso antes da execução de qualquer ferramenta?