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, который:
- Выполняет произвольный код (Python / TypeScript / shell / etc.) и возвращает stdout / результат.
- Не даёт коду читать секреты / писать на диск / ходить в сеть / вешать машину циклом / съесть всю память / вырваться в 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 достаточно.vm2— deprecated 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 toolsexecute_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 start | RAM (10 параллельных) | Изоляция | Ops | Когда выбирать |
|---|---|---|---|---|---|
Mastra LocalSandbox + bwrap | 50-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/isolate | V8 boundary | Средняя (новый container) | Code Mode pattern из коробки, V8-isolates долгосрочно |
| E2B | 150-200ms | их | Firecracker | Низкая (managed) | Когда вендор-managed > self-host |
| Modal | 2-5с | их | gVisor | Низкая | GPU нагрузки, не agent loops |
| gVisor RuntimeClass | hundreds ms | нативный pod | Kernel + 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.
Сноски
-
Slack-тред 2026-04-27 (Никита → Ильдар про sandbox-задачу), accessed 2026-05-17, https://realaicorp.slack.com/archives/C094GRT3CBY/p1777316077295729. ↩
-
Mastra Workspace docs, accessed 2026-05-17, https://mastra.ai/reference/workspace/sandbox — https://mastra.ai/reference/workspace/local-sandbox. ↩
-
Mastra Code Mode RFC (open), accessed 2026-05-17, https://github.com/mastra-ai/mastra/issues/11036. ↩
-
isolated-vmREADME, accessed 2026-05-17, https://github.com/laverdet/isolated-vm/blob/main/README.md. ↩ -
workerdrepo, accessed 2026-05-17, https://github.com/cloudflare/workerd. ↩ -
Anthropic
sandbox-runtime, accessed 2026-05-17, https://github.com/anthropic-experimental/sandbox-runtime. ↩ -
Anthropic Code Execution with MCP, accessed 2026-05-17, https://www.anthropic.com/engineering/code-execution-with-mcp. ↩
-
Cloudflare Code Mode, accessed 2026-05-17, https://blog.cloudflare.com/code-mode/. ↩
-
Cloudflare Dynamic Workers Open Beta (April 2026, InfoQ), accessed 2026-05-17, https://www.infoq.com/news/2026/04/cloudflare-dynamic-workers-beta/. ↩
-
CodeAct paper (Wang et al, ICML 2024), accessed 2026-05-17, https://arxiv.org/abs/2402.01030. ↩
-
MedAgentBench (paper + repo, оригинальная парадигма агента; в paper’е sandbox нет, REST-only), accessed 2026-05-17, https://github.com/stanfordmlgroup/MedAgentBench. ↩
-
Northflank “How to sandbox AI agents in 2026”, accessed 2026-05-17, https://northflank.com/blog/how-to-sandbox-ai-agents. ↩
-
Anthropic Claude Code sandboxing (engineering blog), accessed 2026-05-17, https://www.anthropic.com/engineering/claude-code-sandboxing. ↩
-
Cursor Agent sandboxing, accessed 2026-05-17, https://cursor.com/blog/agent-sandboxing. ↩