TuBrief
구독 채널
비디오
커뮤니티

Почему нельзя давать мастер-ключ агентам Node.js и как реализовать 60-секундные временные токены

TuBrief 편집팀
2026년 7월 23일
0
Computing/Software

원본 영상을 바탕으로 AI의 도움을 받아 작성했습니다. 원본 영상이 기준입니다.

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

관련 영상

Ship 26 NYC - Не давайте своему агенту мастер-ключ17:22

Ship 26 NYC - Не давайте своему агенту мастер-ключ

Vercel

커뮤니티의 다른 글

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

2026년 9월 13일

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

2026년 9월 13일

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

2026년 9월 13일

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

2026년 9월 13일

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

2026년 9월 12일

Apple Won the AI Race

2026년 9월 12일

댓글 (0)

Log in to leave a comment

아직 작성된 글이 없습니다

© 2026 . All rights reserved.

TuBrief
구독 채널
비디오
커뮤니티
로그인

Почему нельзя давать мастер-ключ агентам Node.js и как реализовать 60-секундные временные токены

При создании автономных агентов с помощью LangChain или LlamaIndex неизбежно наступает момент, когда их нужно связать с базой данных и внешними API. И именно здесь чаще всего происходят инциденты. Из-за одной инъекции промпта (Prompt Injection) мастер-ключ OpenAI или пароль администратора БД, прописанные в .env, тут же утекают в сеть. И сколько бы гардрайлов (guardrails) для промптов вы ни выстраивали, это не поможет. Пока область рассуждений LLM жестко связана с областью выполнения, безопасность рушится буквально от одной фразы.

Согласно отчету Google SAIF (Secure AI Framework) за 2025 год, 88% компаний, внедряющих агентов, сталкивались с попытками инъекции промпта. При этом уровень блокировки традиционными методами обнаружения текстовых шаблонов составил всего 23%. Гораздо проще сразу не доверять самому процессу агента. Лучше вообще не давать агенту постоянных прав, а изменить архитектуру так, чтобы на уровне промежуточного ПО (middleware) внедрялся временный токен со сроком жизни 60 секунд.

Внедрение 60-секундного токена Dynamic Vault в Express

Используя аутентификацию AppRole в HashiCorp Vault, можно выпускать токен на 60 секунд ровно в момент вызова инструмента. Когда агент обращается к внешнему API, перехватчик (interceptor) вмешивается в процесс и подставляет Short-lived токен в заголовок запроса.

`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;
  }
};

}
}

`

Написанием одного лишь кода дело не ограничивается. Куча памяти (heap) движка Node.js V8 очищается сборщиком мусора непредсказуемо, поэтому даже после обнуления переменной строка токена некоторое время остается в памяти. При атаке с дампом кучи возникает риск утечки.

  1. Как только получен ответ API, сразу же помещаем чувствительное значение в объект Buffer.
  2. По завершении выполнения запускаем Buffer.fill(0), чтобы принудительно очистить байты в 0.
  3. Присваиваем ссылочной переменной значение null, передавая её «на съедение» GC.

Соблюдение этих трех шагов существенно снижает вероятность утечки токена при профилировании памяти.

Метод управления учетными данными Средний срок жизни (TTL) Область ущерба при компрометации Аудит и трассировка
Жестко закодированный Master API Key Неограничен Полный захват всей инфраструктуры Идентификация субъекта невозможна из-за общего ключа
Static Secret в переменных окружения (.env) Срок жизни процесса Злоупотребление всеми правами данного процесса Node Невозможно отследить рабочие процессы отдельных пользователей
Vault AppRole Ephemeral Token 60 секунд Ограничено 1 однократным запуском инструмента Посекундная трассировка через Vault Audit Log

Передача Auth0 OIDC Claim в политики PostgreSQL RLS

Даже если из-за побега из промпта (jailbreak) агент выполнит команду “выведи информацию обо всех пользователях”, достаточно, чтобы сам движок БД отклонил этот запрос. В мультиарендной (Multi-tenant) SaaS-среде необходимо настроить Row Level Security (RLS) в PostgreSQL.

Извлекаем userId и tenantId из JWT, выданного Auth0, и передаем их в контекст сессии RunnableConfig в LangChain. Затем внедряем этот контекст в качестве переменных сессии внутри транзакции 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);

});
}

`

В качестве последнего аргумента set_config обязательно нужно передать true, чтобы переменная применялась только в области текущей транзакции (SET LOCAL). Это ключевая настройка, предотвращающая утечку прав предыдущего пользователя следующему запросу в условиях пула соединений БД.

Теперь создаем политику в SQL-файле, которая считывает эти переменные сессии.

`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
);

`

Благодаря такой комбинации, какие бы странные запросы ни генерировал агент, он не сможет даже прочитать данные за пределами своего тенанта. Даже в случае утечки время восстановления данных (MTTR) сократится с нескольких дней до считанных минут.

Пайплайн валидации CI/CD с использованием Promptfoo и PyRIT

Каждый раз, когда разработчик меняет код инструментов агента, тестировать изоляцию прав вручную невозможно. Мы объединяем open-source инструменты Promptfoo и Microsoft PyRIT в GitHub Actions для проверки на уровне PR.

`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

`

На сервере в рантайме подключаем middleware предохранителя (Circuit Breaker), который сразу же останавливает работу при обнаружении паттернов угроз.

`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+roles+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(() => {});

}
}

`

Порядок построения пайплайна тестирования безопасности прост:

  1. Поместите promptfooconfig.yaml в корень проекта и определите проверки jailbreak и excessive-agency.
  2. Настройте воркфлоу отслеживания PR в GitHub Actions для запуска сценариев Promptfoo и PyRIT.
  3. Разместите middleware AgentCircuitBreaker перед эндпоинтами Express, чтобы останавливать выполнение агента при обнаружении 3 подряд паттернов инъекции.

С такой конфигурацией вы сэкономите более 5 часов, которые раньше еженедельно тратились на ручной анализ промптов.

Метрика оценки Ручной способ проверки Внедрение автоматизации Zero-Trust
Время подготовки к аудиту 5–8 часов в неделю Менее 1 часа в неделю
MTTR при утечке прав Несколько дней (полный анализ логов/БД) Считанные минуты (ограничено рамками RLS)
Уровень блокировки инъекций промпта Около 23% 99.9%
Риск расходов при утечке ключа Неограниченные счета за облако Счета заблокированы благодаря TTL 60 сек

Суть безопасности агентов заключается не в том, чтобы молиться на послушание модели. Она в том, чтобы на уровне инфраструктуры надеть на неё наручники, которые не позволят нанести вред системе, даже если модель начнет галлюцинировать или поддастся атаке.