Status: research / not deployed в BloodGPT. Страница фиксирует наш разбор апрель 2026 — что такое sandbox для исполнения произвольного кода, какие категории решений бывают, какие подходят нам и почему. Существует чтобы code-mode-pattern и связанные обсуждения могли ссылаться на конкретные опции без повторения research.

Технологии (bwrap, isolated-vm, workerd, gVisor, Firecracker и т.д.) — общие primitive’ы изоляции untrusted-кода, использующиеся в dev environments (Replit), edge runtime (Cloudflare Workers), CI runners, plugin-системах, security testing. К LLM не привязаны. Наш текущий триггер — Никитин FHIR-агент в Realai-plus/fhir-services (ветка feature/medagentbench-agent), у которого тул execute_python_code исполняет LLM-сгенерённый код через голый Python exec() с whitelist builtins. Это приемлемо для бенчмарка, не приемлемо для production. Если в будущем появится другой use case (untrusted plugin от lab-партнёра, sandboxed eval-runner для бенчмарков, изолированное исполнение пользовательских формул и т.п.) — тот же набор технологий применим, разбор переиспользуется.

Авторская рамка задачи (Ильдар, Slack 2026-03-12): “Получится наш маленький Клод код который может все. Главное придумать еще, чтобы это было безопасно.” Эта страница — про вторую часть. Контекст всей миграции на agent-based + code execution — в code-mode-pattern раздел “Применимость к BloodGPT”.

Контекст — что вообще “sandbox” для исполнения кода

Sandbox — runtime, который:

  1. Выполняет произвольный код (Python / TypeScript / shell / etc.) и возвращает stdout / результат.
  2. Не даёт коду читать секреты / писать на диск / ходить в сеть / вешать машину циклом / съесть всю память / вырваться в host.

Sandbox = runtime + изоляция + лимиты. Технологий десятки, разной “толщины” изоляции и стоимости.

В кейсе LLM-агента (наш текущий триггер) изоляция должна быть быстрой — cold-start ms, не секунды, потому что вызов sandbox случается в каждой итерации agent loop. Это сужает выбор. Для других use case (запустили один untrusted job на несколько часов) tradeoff другой — managed-сервисы становятся приемлемыми.

Threat model — что мы реально защищаем

Threat model зависит от use case. Технологии sandbox идентичны, но “толщина” изоляции которую стоит покупать — разная.

Для нашего текущего триггера (LLM-агент, semi-trusted генерация кода) — угрозы по убыванию вероятности:

  • LLM нагенерил кривой код → бесконечный цикл / fork bomb / memory bomb. Случается естественно, не нужен злой умысел.
  • Prompt-injection из FHIR-данных пациента → код пытается exfiltrate. В narrative diagnosis может быть injection-payload; LLM может его инкорпорировать в код.
  • Сетевой запрос наружу из кода. LLM сама может догадаться (особенно если в промпте упоминаются URL).
  • Чтение env / соседних файлов. Утечка секретов.
  • Escape из sandbox в host-процесс. V8/CPython escapes — research-grade, нулевые дни. Низкая вероятность.

Вывод для LLM-кейса: реальный риск — accidental misbehavior + prompt-injected misuse, не “хакер ломает V8”. Sandbox должен жёстко лимитировать CPU/RAM/time + блокировать сеть/диск; defence против нулевых дней (microVM, гипервизор) — overkill для нашей нагрузки.

Для других гипотетических use case угрозы другие:

  • Untrusted plugin от lab-партнёра — actor может быть adversarial; нужна kernel/hypervisor isolation (gVisor, Firecracker), defence-in-depth.
  • User-uploaded eval scripts для бенчмарков — между LLM-кейсом и plugin-кейсом; зависит от того, кто аплоадит (наша команда vs внешние).
  • Isolated math-formula evaluator — наоборот, можно AST-whitelist (clinical-calc-agent уже делает это для clinical formulas); полноценный sandbox избыточен.

Полная threat-model таблица для LLM-кейса — в research-доке (см. Источники).

Категории runtime’ов

In-process JS isolate

Создаёт отдельный V8-isolate в том же Node-процессе. Свой heap, своё globalThis, свой event loop. Нет require, process, fs, fetch пока сам не прокинешь. Латентность — миллисекунды (V8 уже загружен), память — десятки MB на isolate.

  • isolated-vm — npm-пакет (native addon). Прод-юзеры: Screeps, Fly.io edge, Algolia, Tripadvisor. Maintenance mode (новых фич нет, но баги фиксят). Memory limit “guideline, not strict” — V8 OOM может уронить весь Node-процесс, поэтому README прямо рекомендует держать в отдельном child-процессе.
  • workerd — open-source runtime Cloudflare Workers (C++, V8 встроен). Production-grade, активно развивается. Все встроенные API в native-коде и шарятся между isolates → меньше памяти на isolate чем у isolated-vm. Запускается как отдельный server (workerd serve config.capnp), не Node-библиотека. Cloudflare сами признают: “workerd is not a hardened sandbox” — для untrusted multi-tenant они оборачивают в Firecracker. Для нашей threat model — V8 isolation достаточно.
  • vm2deprecated July 2023, CVE-2026-22709 (CVSS 9.8). Не использовать.
  • node:vm стандартный — не security boundary. Документированные escapes через прототипы. Только для trusted DSL.

OS namespace / kernel-level isolation

Subprocess в изолированном namespace ядра (mount / PID / network / user). Изоляция сильнее чем V8 (kernel-level), но каждый запуск = fork + старт интерпретатора → латентность ~50-200ms, память 80-100MB на subprocess.

  • bubblewrap (bwrap) — Linux namespace sandbox, userspace. Использует clone() с флагами unshare. Базовый образ GKE-нод его обычно содержит.
  • Mastra LocalSandbox — обёртка над bwrap (Linux) и sandbox-exec / seatbelt (macOS) с pluggable provider’ами. Ши́пится в @mastra/core@1.1.0 (наша версия в production analysis-worker). Auto-registers tools execute_command / get_process_output / kill_process в Mastra-агенте. Подробнее — mastra.
  • anthropic-experimental/sandbox-runtime — то же что Mastra LocalSandbox под капотом (bwrap + seccomp BPF + namespaces / seatbelt), но как отдельная библиотека. Apache 2.0, активно развивается под Claude Code. Богаче политика (allowed domains, writable directories), есть CLI (srt).
  • nsjail — Google internal, Windmill production. Самый дешёвый Linux untrusted-process jail.
  • firejail — userspace sandbox, setuid root binary. На server без X11 рискованно.

Sidecar runtime

Отдельный процесс / контейнер, агент общается через HTTP/RPC на localhost. Сочетает изоляцию с сохранением warm pool isolate’ов.

  • workerd как sidecar на GKE — отдельный container в pod’е analysis-worker, capnp-конфиг через ConfigMap, агент → localhost:8787. ~5ms latency на вызов (loopback + V8 isolate), ~50MB idle + ~10MB на isolate. Полная схема deployment + Inngest interplay — в research-доке.
  • Cloudflare agents-sdk + workerd — реализация code-mode-pattern из коробки (типизированные RPC к нашим тулам).

Managed cloud sandboxes

Sandbox-as-a-service у внешнего вендора. Для агентов с короткими циклами обычно неудачный выбор: network round-trip × N итераций уничтожает latency-бюджет. Для долгих/редких задач — оправдано.

  • E2B (Firecracker microVM-as-service) — 150-200ms cold, ~$0.05-0.10/min, vendor lock, недавние reliability incidents. Стандарт индустрии для AI-агентов “из коробки”.
  • Modal Sandbox (gVisor containers) — заявляет sub-second, реально 2-5с cold. Убивает 20-итерационный цикл. Хорош для GPU.
  • Vercel Sandbox (Firecracker) — $0.128/CPU-hr, cross-cloud latency (мы на GCP, Vercel на AWS). Хорош когда уже на Vercel.
  • Cloudflare Sandboxes (V8 isolate / containers на edge) — <5ms cold, но мы на GKE — RTT в Cloudflare network на каждый exec бессмысленный. Имеет смысл если агент крутится в Workers.
  • Daytona (Docker, <90ms cold) — быстрее E2B, но изоляция слабее (контейнер ≠ kernel namespace).
  • Blaxel — native Mastra integration, но менее зрелый.

Heavy isolation (kernel / hypervisor)

Для нашего workload (filter JSON-словаря в памяти, ноль syscalls) — overkill. Указаны для полноты.

  • Firecracker напрямую — 125ms cold, snapshot 28ms. Operational burden — нужно крутить на bare metal или nested virt.
  • Kata Containers — гипервизор + K8s, 1с cold. Сложная установка на GKE node pool.
  • gVisor RuntimeClass на GKE — user-space ядро перехватывает syscalls, ~30% I/O overhead. Защищает то, чем мы не пользуемся (наш код syscalls почти не делает).
  • K8s Job per exec — 3-10с pod startup. Комично для agent loop.

WASM / альтернативные

  • Pyodide в Node — CPython в WebAssembly. ~1-2с cold-init, нужен warm pool. Имеет смысл если остаёмся на Python.
  • WebContainers (Bolt/StackBlitz tech) — Node в WASM в браузере. Server-side не наш кейс.
  • Deno subprocess --allow-none — TS-native, deny-by-default permissions. ~150-300ms cold, +50MB image — новая runtime в кластере.

Не использовать

  • vm2 — deprecated, CVE-2026-22709 (CVSS 9.8).
  • node:vm — не security boundary (доки Node).
  • smolagents LocalPythonExecutor — их же доки говорят “не sandbox”. Кто использует как sandbox — один prompt-injection от RCE.

Сравнительная таблица — для нашего кейса

ОпцияCold startRAM (10 параллельных)ИзоляцияOpsКогда выбирать
Mastra LocalSandbox + bwrap50-200ms~800MB-1GB (subprocess)Kernel namespaceОчень низкая (уже установлено)Минимальный sandbox, tool calling парадигма
isolated-vmµs-2ms warm~50-500MB (in-process)V8 boundaryНизкая (npm dep)µs latency, in-process, TS-only
workerd sidecar~5ms~50MB + 10MB/isolateV8 boundaryСредняя (новый container)Code Mode pattern из коробки, V8-isolates долгосрочно
E2B150-200msихFirecrackerНизкая (managed)Когда вендор-managed > self-host
Modal2-5сихgVisorНизкаяGPU нагрузки, не agent loops
gVisor RuntimeClasshundreds msнативный podKernel + syscall wrapВысокаяКогда нужен kernel-level isolation на K8s

Полная таблица + обоснование почему что отбрасываем — в research-доке.

Что у нас есть (gap analysis)

  • Mastra Workspace + LocalSandbox уже в установленной версии (@mastra/core@1.1.0). Не используется ни одним из 5 production-агентов. Полная справка — mastra раздел “Workspace + Sandbox primitive”.
  • AST-whitelist evaluator в clinical-calc-agent/src/medcalc_parser/calc_tools.py:51-114 — только для math-формул, не для произвольного кода.
  • Inngest step.run — orchestration слой, обеспечивает retry/persistence/observability на уровне step. Ортогонален sandbox-выбору; agent loop живёт внутри одного step.run. См. inngest.
  • GKE gVisor RuntimeClass — НЕ поднят. Если бы выбрали kernel-level isolation, потребовалась бы инфра-работа.
  • child_process.exec в apps/benchmark — process isolation для PDF→image, не для untrusted кода.

Готового решения для “выполни LLM-сгенерённый код безопасно” нет — строим с нуля или подключаем Mastra LocalSandbox.

Связанные концепты

  • code-mode-pattern — индустриальная парадигма агентского tool-calling (типизированные bindings, code-emitting); влияет на требования к runtime (Code Mode хочет in-process RPC, tool calling работает с любым subprocess sandbox).

Открытые вопросы

  • Бенчмарк latency и token-cost на реальных сценариях — без этого “выберем bwrap или workerd” — спекуляция. См. open questions в code-mode-pattern.
  • Multi-tenant изоляция между вызовами разных org/пациентов — нужен ли cross-call wipe? Не критично сейчас, всплывёт при scale.
  • Trust boundary для prompt-injected данных — sandbox защищает от исполнения, не от того что код написал не то. Открытый вопрос как валидировать сгенерённый код перед exec.
  • Observability — каждый exec в Langfuse как отдельный span, или агрегированно? Influences debugging cost.
  • Где живёт sandbox в архитектуре — библиотека внутри агентского пакета или отдельный микросервис? Зависит от парадигмы (см. decision).

Связано

  • mastra — наш agent host, шипит WorkspaceSandbox + LocalSandbox (bwrap/seatbelt) в установленной версии
  • inngest — orchestration слой ортогонален выбору runtime’а
  • code-mode-pattern — emerging industry-идея про code-emitting агентов; от парадигмы агента зависит подходящий runtime (code-emitting хочет in-process RPC, tool calling работает с любым subprocess sandbox)

Источники

Источники: 1 2 3 4 5 6 7 8 9 10 11 12 13 14.

Сноски

  1. Slack-тред 2026-04-27 (Никита → Ильдар про sandbox-задачу), accessed 2026-05-17, https://realaicorp.slack.com/archives/C094GRT3CBY/p1777316077295729.

  2. Mastra Workspace docs, accessed 2026-05-17, https://mastra.ai/reference/workspace/sandboxhttps://mastra.ai/reference/workspace/local-sandbox.

  3. Mastra Code Mode RFC (open), accessed 2026-05-17, https://github.com/mastra-ai/mastra/issues/11036.

  4. isolated-vm README, accessed 2026-05-17, https://github.com/laverdet/isolated-vm/blob/main/README.md.

  5. workerd repo, accessed 2026-05-17, https://github.com/cloudflare/workerd.

  6. Anthropic sandbox-runtime, accessed 2026-05-17, https://github.com/anthropic-experimental/sandbox-runtime.

  7. Anthropic Code Execution with MCP, accessed 2026-05-17, https://www.anthropic.com/engineering/code-execution-with-mcp.

  8. Cloudflare Code Mode, accessed 2026-05-17, https://blog.cloudflare.com/code-mode/.

  9. Cloudflare Dynamic Workers Open Beta (April 2026, InfoQ), accessed 2026-05-17, https://www.infoq.com/news/2026/04/cloudflare-dynamic-workers-beta/.

  10. CodeAct paper (Wang et al, ICML 2024), accessed 2026-05-17, https://arxiv.org/abs/2402.01030.

  11. MedAgentBench (paper + repo, оригинальная парадигма агента; в paper’е sandbox нет, REST-only), accessed 2026-05-17, https://github.com/stanfordmlgroup/MedAgentBench.

  12. Northflank “How to sandbox AI agents in 2026”, accessed 2026-05-17, https://northflank.com/blog/how-to-sandbox-ai-agents.

  13. Anthropic Claude Code sandboxing (engineering blog), accessed 2026-05-17, https://www.anthropic.com/engineering/claude-code-sandboxing.

  14. Cursor Agent sandboxing, accessed 2026-05-17, https://cursor.com/blog/agent-sandboxing.