Modern Angular
Segurança de WebMCP no Angular: o agente que chama suas tools pode ser sequestrado
Uma WebMCP tool é uma função no seu app Angular publicado que um agente de IA consegue chamar sem um humano clicar. O detalhe que ninguém projeta: esse agente lê páginas, então pode ser conduzido por conteúdo que o usuário nunca confiou, e o seu execute roda com a sessão do usuário. O Angular não valida as entradas do agente contra o seu schema, então a superfície de tools é um endpoint autenticado com um chamador que você não controla.
O modelo de ameaça em uma frase
Uma WebMCP tool é uma capacidade que você entregou pro agente de IA que o usuário estiver rodando, e esse agente lê páginas. O risco todo sai daí. O agente pode estar carregando instruções que pegou em algum lugar que o usuário nunca checou, uma review, um comentário, uma thread de suporte, um PDF, e essas instruções podem mandar ele chamar a sua tool findOrder ou cancelSubscription. Isso é prompt injection chegando numa função de verdade do seu app, e a tool não distingue um pedido que o usuário quis de um que uma página hostil plantou.
Agora some a parte que deixa isso afiado. O seu execute roda no browser do usuário, dentro da sessão do usuário, com os cookies e tokens do usuário. Um agente sequestrado chamando a sua tool age com a autoridade do usuário, com instruções que o usuário nunca deu. É essa a régua de toda decisão daqui pra frente: trate cada tool exposta como um endpoint público e autenticado cujo chamador é hostil, porque, na prática, é isso que ela é.
A mecânica de registrar tools, bootstrap, rota, service ou um Signal Form, está no guia de setup do WebMCP. Isto aqui é a camada de segurança que fica em cima, e é a parte que eu não publicaria sem.
O schema é documentação, não fronteira de confiança
O primeiro instinto é se apoiar no inputSchema. Não se apoie. O Angular é explícito: ele não valida que as entradas que o agente passa de fato batem com o JSON schema declarado. O schema diz ao agente como chamar a tool; ele não barra nada. Um agente sequestrado, ou só confuso, pode entregar ao seu execute uma string onde você declarou número, um id de um registro que este usuário não pode ver, ou um payload três campos maior do que você esperava.
Então a validação é trabalho seu, no topo de todo execute, antes das entradas tocarem em qualquer coisa. Faça o parse, não assuma. Recuse o que você não declarou. Confira que o id pertence a algo que este usuário tem permissão de ler. É a mesma postura que você teria com um corpo de request de um cliente não confiável, porque o agente é exatamente isso.
execute: (raw) => {
// O Angular não impõe o inputSchema. Valide antes de tudo.
const orderId = String(raw?.orderId ?? '');
if (!/^[A-Z0-9-]{6,20}$/.test(orderId)) {
return { content: [{ type: 'text', text: 'Id de pedido inválido.' }] };
}
const orders = inject(Orders);
// Autorize para ESTE usuário no servidor, não só aqui no browser.
return { content: [{ type: 'text', text: orders.summaryForCurrentUser(orderId) }] };
},Menor privilégio: leia antes de escrever, confirme antes do estrago
O controle de segurança mais barato é não expor a tool. Um agente que consulta um pedido é um risco diferente de um que cancela o pedido. Comece só-leitura. Uma tool que lê e devolve dado tem um raio de impacto limitado; uma tool que altera, cobra, apaga ou concede acesso entrega a um chamador automatizado, e talvez sequestrado, uma alavanca no seu negócio.
Quando uma tool precisa alterar dado, ponha um humano no meio. O agente pode preparar a ação, preencher o formulário, dizer qual pedido cancelar, mas uma pessoa confirma antes de efetivar. Expor um Signal Form como tool encaixa direitinho aqui: o agente preenche os campos e o usuário revisa e envia, em vez de o agente chamar um execute que dispara e esquece.
Mantenha enxuto também o que você devolve. Uma tool que responde findUser e devolve o registro inteiro acabou de deixar todo campo, email, telefone, flags internas, ao alcance do agente e de quem está conduzindo ele. Devolva o mínimo que a tarefa precisa, não a linha toda.
| O que a tool faz | Decisão padrão | Trava |
|---|---|---|
| Lê dado não sensível | Exponha | Mesmo assim valide a entrada e dê escopo no usuário |
| Lê PII ou dado interno | Exponha com cuidado | Devolva o mínimo; autorize por registro |
| Altera estado (update, cancel) | Humano no meio | O agente prepara, o usuário confirma antes de efetivar |
| Dinheiro, identidade, destrutivo, concede acesso | Não exponha ainda | Deixe fora da superfície WebMCP enquanto é experimental |
Autorize no servidor, dê escopo no cliente
Dois controles, dois lugares, e eles não se substituem. No cliente, o exposedTo limita quais origens podem chamar uma tool, a mesma lógica do CORS, e um AbortSignal derruba a tool quando o contexto dela acaba. Ponha o exposedTo no conjunto mais estreito que você consiga justificar. Mas é uma cerca do lado do cliente, e cerca do lado do cliente não autoriza.
A autorização que vale está no servidor. O seu execute roda com a sessão do usuário, então a chamada chega no seu backend já autenticada como o usuário. É justamente por isso que você revê, no servidor, se este usuário pode fazer esta coisa neste registro, a cada chamada, igual a qualquer outro request. O browser não é fronteira de confiança, e um agente dentro do browser é menos ainda.
Aproveite e fique de olho no ciclo de vida. Uma tool que sobrevive à própria rota é superfície exposta que você esqueceu que tinha. O cleanup com escopo de rota é o mecanismo pra isso, e o bug aberto de tool duplicada em volta dele é um bom lembrete de testar de verdade se as tools se desregistram quando você navega pra fora, em vez de supor que sim.
O que eu ainda não publicaria
Tudo isso está em cima de uma API experimental sobre uma spec em rascunho. O ponto de entrada já saiu de navigator para document.modelContext no meio do ciclo, e a doc avisa que as APIs podem mudar fora de major. Pra segurança isso dobra a cautela: você está endurecendo uma superfície cujo formato pode mudar debaixo de você, então o que você expõe é o que você re-audita a cada minor do Angular, não só nos majors.
Onde eu fico: faço spike de tools só-leitura atrás de uma flag, em rotas internas ou de baixo risco, e trato o trabalho de segurança como a entrega de verdade, a validação de entrada, a autorização no servidor, o padrão de humano no meio pra qualquer coisa que escreve. Isso sobrevive aos renames da API. O que eu não colocaria no app público é uma tool que mexe em dinheiro, muda identidade ou faz algo destrutivo, enquanto o chamador é um agente que pode ser convencido de qualquer coisa e a spec por baixo ainda é rascunho. A ideia é boa. O chamador é que ainda não é confiável.
Artefato para reaproveitar
Checklist de segurança WebMCP para Angular
- Trate cada tool exposta como um endpoint público e autenticado com um chamador hostil.
- Valide toda entrada do execute em runtime; o Angular não impõe o JSON schema.
- Comece só-leitura; não exponha ainda tool que mexe em dinheiro, muda identidade ou apaga dado.
- Ponha um humano no meio em qualquer alteração: o agente prepara, o usuário confirma.
- Reveja a autorização no servidor a cada chamada; a sessão do browser não é fronteira de confiança.
- Ponha o exposedTo nas origens mais estreitas, e confirme que tool com escopo de rota se desregistra mesmo.
- Devolva o mínimo de dado que a tarefa precisa; retorno largo é caminho de vazamento.
- Re-audite a superfície exposta a cada minor do Angular, não só nos majors.
Perguntas frequentes
Qual é o risco específico do WebMCP, além da segurança web normal?
O chamador é um agente de IA que lê páginas, então pode estar carregando instruções injetadas de conteúdo que o usuário nunca confiou. O seu execute roda com a sessão do usuário, então um agente sequestrado age com a autoridade do usuário, com instruções que o usuário nunca deu.
O JSON schema basta para validar as entradas do agente?
Não. O Angular afirma que "not provide any implicit validation that the inputs provided by an agent actually match the defined JSON schema." Valide os argumentos no topo de todo execute e recuse qualquer coisa que você não declarou.
O exposedTo deixa uma tool segura?
Não. O exposedTo limita quais origens podem chamar a tool, como o CORS, mas é um controle do lado do cliente, não autorização. Reveja no servidor se este usuário pode executar esta ação, a cada chamada.
Dá para expor uma tool de pagamento ou de exclusão com WebMCP?
Ainda não. Enquanto a API é experimental e o chamador pode ser sequestrado por prompt injection, deixe tools que mexem em dinheiro, mudam identidade ou apagam dado fora da superfície, ou trave atrás de confirmação humana explícita.
Fontes consultadas
- https://next.angular.dev/ai/webmcp
- https://next.angular.dev/api/core/provideExperimentalWebMcpTools
- https://webmachinelearning.github.io/webmcp/
- https://angular.dev/ai/mcp
- https://angular.dev/guide/forms/signals/overview
- https://angular.dev/reference/releases
- https://owasp.org/www-project-top-10-for-large-language-model-applications/
Modern Angular Playbook
Este artigo é um play.
O Playbook do Angular Moderno reúne o diagnóstico, a matriz de adoção, onze jogadas e o plano de 30 dias. Grátis, em inglês e português.
Você recebe os dois PDFs por email, pela lista do Dojo IA.
André Ramosdisponível para vagas remotas, UTC−3Entre em contato →