TuBrief
Subscribed Channels
Videos
Community

Por que você não deve dar uma chave mestra para um agente Node.js e como implementar um token temporário de 60 segundos

TuBrief Editorial
July 23, 2026
0
Computing/Software

Written with AI assistance from the source video. The video is the authority.

Português한국어EnglishEspañolहिन्दीFrançaisDeutsch日本語РусскийBahasa Indonesia中文العربية

Related Video

Ship 26 NYC - Não dê a chave mestre ao seu agente17:22

Ship 26 NYC - Não dê a chave mestre ao seu agente

Vercel

More from the community

사내 시스템에 llm api 붙일 때 마주하는 현실적인 한계와 대응법

September 13, 2026

레거시 백엔드에 GPT-6 Astra 붙일 때 예산 승인과 보안 통과를 먼저 끝내는 법이 있습니다

September 13, 2026

에이전트끼리 대화하다 6천만 원 청구서가 나오는 이유

September 13, 2026

사내 RAG 벡터 검색에 Okta 권한 필터를 직접 거는 방법

September 13, 2026

브라우저 에이전트에게 내 구글 계정을 통째로 넘기면 안 되는 이유

September 12, 2026

Apple Won the AI Race

September 12, 2026

Comments (0)

Log in to leave a comment

No posts yet

© 2026 . All rights reserved.

TuBrief
Subscribed Channels
Videos
Community
Log in

Por que você não deve dar uma chave mestra para um agente Node.js e como implementar um token temporário de 60 segundos

Ao criar agentes autônomos com LangChain ou LlamaIndex, eventualmente chega o momento de conectá-los a bancos de dados e APIs externas. É aqui que os incidentes costumam acontecer. Com um único prompt injection, a chave mestra da OpenAI ou a senha de administrador do banco de dados salvas no .env podem ser expostas. Não importa o quão rigorosos sejam os seus guardrails de prompt: enquanto a lógica de raciocínio e a execução do LLM estiverem acopladas, a segurança pode ser comprometida por uma simples frase.

De acordo com o relatório SAIF (Secure AI Framework) de 2025 do Google, 88% das empresas que adotaram agentes enfrentaram tentativas de prompt injection. A taxa de bloqueio das técnicas tradicionais de detecção de padrões de texto foi de apenas 23%. É mais seguro simplesmente não confiar no próprio processo do agente. Em vez de conceder permissões diretas ao agente, a estrutura deve ser alterada para injetar tokens temporários com vida útil de apenas 60 segundos na camada de middleware.

Implementando injeção de token dinâmico de 60 segundos do Vault no Express

Utilizando a autenticação AppRole do HashiCorp Vault, você pode emitir um token de 60 segundos exatamente no momento em que uma ferramenta é chamada. Quando o agente faz uma requisição a uma API externa, um interceptor intervém e insere o token de curta duração no cabeçalho.

`typescript
import { Request, Response, NextFunction } from 'express';
import vault from 'node-vault';

interface VaultAppRoleAuth {
roleId: string;
secretId: string;
}

export class EphemeralTokenInjector {
private vaultClient: any;
private roleId: string;
private secretId: string;

constructor(endpoint: string, auth: VaultAppRoleAuth) {
this.vaultClient = vault({ endpoint });
this.roleId = auth.roleId;
this.secretId = auth.secretId;
}

private async getAppRoleToken(): Promise {
const result = await this.vaultClient.approleLogin({
role_id: this.roleId,
secret_id: this.secretId,
});
return result.auth.client_token;
}

public createToolInterceptor(targetServiceRole: string) {
return async (req: Request, res: Response, next: NextFunction) => {
let clientToken: string | null = null;
try {
clientToken = await this.getAppRoleToken();

    const dynamicSecret = await this.vaultClient.write(
      `sys/leases/generate/${targetServiceRole}`,
      { ttl: '60s' }
    );

    req.headers['authorization'] = `Bearer ${dynamicSecret.data.token}`;
    req.body.ephemeralContext = {
      leaseId: dynamicSecret.lease_id,
      expiresAt: Date.now() + 60000,
    };

    next();
  } catch (error) {
    res.status(500).json({ error: 'Failed to inject ephemeral dynamic secret' });
  } finally {
    clientToken = null;
  }
};

}
}

`

Apenas escrever o código não é suficiente. Como a memória Heap do motor V8 do Node.js é gerenciada pelo Garbage Collector de forma não determinística, a string do token permanece na Heap por algum tempo, mesmo após limpar a variável. Se houver um ataque de heap dump, há risco de vazamento.

  1. Armazene imediatamente os valores sensíveis em um objeto Buffer ao receber a resposta da API.
  2. Após a execução, execute Buffer.fill(0) para forçar a limpeza dos bytes para zero.
  3. Atribua null à variável de referência para disponibilizá-la para o Garbage Collector.

Seguir esses três passos reduz drasticamente a probabilidade de o token ser roubado via perfilamento de memória.

Método de gerenciamento de credenciais Tempo de vida médio (TTL) Alcance dos danos em caso de vazamento Trilha de auditoria
Master API Key hardcoded Ilimitado Domínio total da infraestrutura Impossível identificar o sujeito devido ao compartilhamento de chave única
Static Secret em variável de ambiente (.env) Tempo de vida do processo Abuso de todas as permissões do processo Node correspondente Impossível rastrear fluxos de trabalho por usuário
Vault AppRole Ephemeral Token 60 segundos Limitado a 1 execução da ferramenta correspondente Rastreamento em segundos via Vault Audit Log

Passando Auth0 OIDC Claims para políticas RLS do PostgreSQL

Mesmo que o agente execute um comando como "busque todas as informações de membros" devido a um jailbreak de prompt, o próprio motor do banco de dados pode rejeitá-lo. Em um ambiente SaaS multi-tenant, você deve configurar o Row Level Security (RLS) do PostgreSQL.

Extraia o userId e o tenantId do JWT emitido pelo Auth0 e passe-os para o contexto de sessão do RunnableConfig do LangChain. Em seguida, injete esse contexto como variáveis de sessão dentro de uma transação do Prisma.

`typescript
import { RunnableConfig } from '@langchain/core/runnables';
import { PrismaClient } from '@prisma/client';

export interface AgentUserClaims {
userId: string;
tenantId: string;
}

export async function executeAgentToolWithRLS(
prisma: PrismaClient,
config: RunnableConfig,
dbOperation: (tx: any) => Promise
): Promise {
const claims = config.configurable?.userClaims as AgentUserClaims;

if (!claims || !claims.tenantId || !claims.userId) {
throw new Error('Unauthorized: Missing OIDC Claims in Agent Execution Context');
}

return await prisma.transaction(async (tx) => { await tx.executeRawSELECT set_config('app.current_tenant_id', ${claims.tenantId}, true);
await tx.$executeRawSELECT set_config('app.current_user_id', ${claims.userId}, true);

return await dbOperation(tx);

});
}

`

É essencial passar true como o último argumento de set_config para que a variável seja aplicada apenas ao escopo da transação atual (SET LOCAL). Essa é uma configuração fundamental para evitar o vazamento de permissões do usuário anterior para a próxima requisição em ambientes com pool de conexões de banco de dados.

Agora, crie uma política no arquivo SQL que leia essas variáveis de sessão.

`sql
ALTER TABLE tenant_documents ENABLE ROW LEVEL SECURITY;
ALTER TABLE tenant_documents FORCE ROW LEVEL SECURITY;

CREATE POLICY agent_tenant_isolation_policy ON tenant_documents
FOR ALL
TO authenticated_agent_role
USING (
tenant_id = current_setting('app.current_tenant_id', true)::uuid
)
WITH CHECK (
tenant_id = current_setting('app.current_tenant_id', true)::uuid
);

`

Com essa combinação, não importa o quão anômala seja a consulta gerada pelo agente, ele não conseguirá nem mesmo visualizar dados fora do escopo do seu próprio tenant. Mesmo que ocorra um vazamento, o tempo de recuperação de dados (MTTR) pode ser reduzido de vários dias para apenas alguns minutos.

Pipeline de validação CI/CD usando Promptfoo e PyRIT

Não é viável testar manualmente a conversão do isolamento de permissões toda vez que um desenvolvedor altera o código das ferramentas do agente. Ferramentas open-source como Promptfoo e PyRIT da Microsoft podem ser integradas ao GitHub Actions para realizar verificações a cada Pull Request.

`yaml
name: Agent Red Teaming Security Gate

on:
pull_request:
paths:
- 'src/agents/'
- 'src/tools/
'
- 'prompts/**'

jobs:
security-eval:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

  - name: Setup Node.js
    uses: actions/setup-node@v4
    with:
      node-version: 20
      cache: 'npm'

  - name: Install Dependencies
    run: npm ci

  - name: Run Promptfoo Scan
    uses: promptfoo/promptfoo-action@v1
    with:
      config: 'promptfooconfig.yaml'
      openai-api-key: ${{ secrets.OPENAI_API_KEY }}
      github-token: ${{ secrets.GITHUB_TOKEN }}

  - name: Run PyRIT Multi-Turn Test
    env:
      AGENT_ENDPOINT: 'http://localhost:3000/api/agent'
    run: |
      python -m pip install pyrit
      python scripts/run_pyrit_eval.py --endpoint $AGENT_ENDPOINT --pass-threshold 0.98

`

No runtime do servidor, adicione um middleware de circuit breaker que interrompe a execução imediatamente ao detectar padrões de ameaça.

`typescript
import { Request, Response, NextFunction } from 'express';

export class AgentCircuitBreaker {
private failureCount: number = 0;
private readonly threshold: number = 3;
private state: 'CLOSED' | 'OPEN' | 'HALF_OPEN' = 'CLOSED';

private forbiddenSignatures: RegExp[] = [
/ignore\s+all\s+previous\s+instructions/i,
/system::override_privileges/i,
/grant\s+role\s+admin/i,
/concat\s*(\s*select/i
];

public middleware() {
return (req: Request, res: Response, next: NextFunction) => {
if (this.state === 'OPEN') {
return res.status(503).json({
error: 'CircuitBreaker:Open - Agent execution halted'
});
}

  const promptInput = JSON.stringify(req.body);
  const isPatternViolated = this.forbiddenSignatures.some(sig => sig.test(promptInput));

  if (isPatternViolated) {
    this.failureCount++;
    this.dispatchSecurityAlert(req.body);

    if (this.failureCount >= this.threshold) {
      this.state = 'OPEN';
    }

    return res.status(403).json({
      error: 'Security Policy Violation: Malicious prompt pattern'
    });
  }

  next();
};

}

private dispatchSecurityAlert(payload: any): void {
const webhookUrl = process.env.SECURITY_WEBHOOK_URL;
if (!webhookUrl) return;

fetch(webhookUrl, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    event: 'AGENT_PRIVILEGE_ESCALATION_DETECTED',
    timestamp: new Date().toISOString(),
    payload
  })
}).catch(() => {});

}
}

`

O processo para construir o pipeline de testes de segurança é simples:

  1. Coloque o arquivo promptfooconfig.yaml na raiz do projeto e defina as verificações de jailbreak e excessive-agency.
  2. Configure um workflow no GitHub Actions acionado por PR para executar os cenários do Promptfoo e PyRIT.
  3. Posicione o middleware AgentCircuitBreaker na frente dos endpoints Express para interromper a execução do agente ao detectar 3 padrões de injeção consecutivos.

Com essa estrutura, você pode economizar mais de 5 horas semanais que seriam gastas na revisão manual de prompts.

Métrica de avaliação Método de verificação manual Com automação Zero-Trust
Tempo de preparação de auditoria 5 a 8 horas por semana Menos de 1 hora por semana
MTTR em caso de vazamento de permissão Vários dias (investigação total de logs/DB) Poucos minutos (limitado pelo escopo do RLS)
Taxa de bloqueio de prompt injection Cerca de 23% 99,9%
Risco de cobrança em caso de vazamento de chave Cobrança ilimitada em nuvem Cobrança bloqueada devido ao TTL de 60s

A chave da segurança para agentes não é rezar para que o modelo se comporte. Trata-se de colocar algemas no nível da infraestrutura para garantir que, mesmo que o modelo alucine ou seja comprometido por um ataque, ele não consiga causar danos ao sistema.