Status: Draft Author: @bdougie Date: 2026-02-28 Project: masterblaster / StereOS
This RFC proposes enabling agents running inside masterblaster VMs to spawn, monitor, and manage other agent VMs — the "agents deploying agents" pattern. An orchestrator agent, given access to the mb CLI, decomposes large tasks into subtasks, provisions child agents in isolated VMs, monitors their progress, handles failures, and aggregates results.
This document covers the architecture, security threat model, required mitigations, and a phased implementation plan.
Today, mb manages single-agent sandboxes launched by humans. The interactive demo at agent-orchestrator-demo illustrates a more powerful pattern: a human launches one orchestrator agent, which autonomously spawns a fleet of specialist child agents — each in its own isolated VM with constrained resources, locked-down networking, and readonly source mounts.
This unlocks:
- Work decomposition: Large tasks (monorepo refactors, multi-service migrations) split across specialist agents
- Failure isolation: One child crashing doesn't affect siblings or the orchestrator
- Autonomous recovery: Orchestrator diagnoses failures, rewrites configs, and redeploys without human intervention
- Resource governance: Each child has explicit CPU/memory/disk budgets
| Capability | Status |
|---|---|
| VM lifecycle (up/down/destroy/ssh/list) | Working |
| jcard.toml config (resources, mounts, secrets, agent) | Working |
| Resource budgets (CPU, memory, disk) | Working |
| Readonly shared mounts | Working |
| Secrets injection via tmpfs | Working |
| Agent harness + restart policy + timeout | Working |
Egress allowlist (egress_allow) |
Parsed, not enforced |
Agent-accessible mb inside VMs |
Not implemented |
completed agent state |
Not implemented |
Uptime/restart tracking in mb list |
Not implemented |
| Parent-child VM relationships | Not implemented |
| Cascading destroy | Not implemented |
The core problem: agents inside VMs need to call mb commands, but the mb CLI talks to the daemon via a host unix socket (~/.mb/mb.sock) that's inaccessible from inside the guest.
Proposed approach: Vsock API Bridge
┌─────────────────── Host ───────────────────┐
│ mb daemon (unix socket: ~/.mb/mb.sock) │
│ ▲ │
│ │ JSON-RPC │
│ ▼ │
│ vsock-bridge (per-VM, listens on vsock) │
│ ▲ │
└───────│─────────────────────────────────────┘
│ vsock
┌───────▼─────────── Guest VM ───────────────┐
│ mb-proxy (translates CLI → vsock RPC) │
│ ▲ │
│ │ │
│ agent (calls `mb up`, `mb list`, etc.) │
└─────────────────────────────────────────────┘
- vsock-bridge (host-side): Per-VM process/goroutine that accepts vsock connections from the guest and proxies allowed commands to the daemon's unix socket
- mb-proxy (guest-side): Lightweight binary installed in the mixtape that presents the same
mbCLI interface but forwards commands over vsock instead of unix socket - Commands are not forwarded raw — the bridge validates and filters them (see Security section)
# Stored in sandbox state (state.json)
{
"name": "auth-agent",
"spawned_by": "orchestrator", # parent sandbox name
"spawn_depth": 1, # nesting depth
"spawn_group": "orchestrator" # root ancestor
}- When a VM calls
mb upthrough the bridge, the bridge injectsspawned_bymetadata mb listgains a--treeflag to show hierarchymb destroy --cascadedestroys a sandbox and all descendants
Current: created → running → stopped | error
Proposed:
created → running → completed (agent exited 0)
→ failed (agent exhausted restarts)
→ stopped (user/parent issued mb down)
→ error (VM-level failure)
completed: agentd reports exit code 0 → stereosd transitions lifecycle → vsock health reports to host → host updates statefailed: agentd reports max_restarts exhausted → same chain- Exposed via
mb listandmb status
The orchestration pattern introduces a privilege escalation surface: a sandboxed agent gains the ability to manage host infrastructure. The threats:
| Threat | Description | Severity |
|---|---|---|
| T1: Unbounded resource consumption | Orchestrator spawns unlimited children, exhausting host CPU/memory/disk | High |
| T2: Lateral movement | Agent destroys/SSHs into VMs it didn't spawn (sibling or unrelated sandboxes) | High |
| T3: Privilege escalation via config | Agent writes a jcard.toml that grants more privileges than its own (wider egress, writable mounts, more resources) | High |
| T4: Secret exfiltration | Agent passes its secrets to child configs, or child configs reference secrets the orchestrator shouldn't distribute | Medium |
| T5: Recursive fork bomb | Orchestrator spawns children that spawn grandchildren indefinitely | High |
| T6: Egress bypass | Without enforcement, egress_allow is cosmetic — agent can exfiltrate data anywhere |
Critical |
| T7: Mount path traversal | Agent writes child jcard.toml with host = "/" or host = "~/.ssh" to access sensitive host paths |
Critical |
| T8: Denial of service via destroy | Compromised agent destroys all VMs on the host | High |
| T9: vsock bridge exploitation | Malformed RPC messages to the bridge crash the daemon or execute arbitrary commands | Medium |
# In orchestrator's jcard.toml
[orchestration]
enabled = true
max_children = 5 # Max direct children
max_depth = 2 # Max nesting (orchestrator → child → no further)
max_total_cpus = 12 # Total CPU budget across all descendants
max_total_memory = "24GiB" # Total memory budget across all descendants
max_total_disk = "100GiB" # Total disk budget across all descendants- The vsock bridge enforces these limits before forwarding
mb upto the daemon - Child
[orchestration]sections are always overwritten by the bridge — a child cannot grant itself more orchestration privileges than its parent allows max_depthprevents recursive spawning beyond the configured limit
- The vsock bridge only allows operations on VMs spawned by the requesting VM
mb listinside a VM only shows that VM's children (not all host VMs)mb ssh <name>only works for that VM's childrenmb destroy <name>only works for that VM's childrenmb down <name>only works for that VM's children- The bridge maps sandbox names to the parent-child graph and rejects out-of-scope requests
Children cannot exceed their parent's privileges:
- Egress: Child
egress_allowmust be a subset of parent'segress_allow - Mounts: Child
[[shared]]hostpaths must be within the parent's allowed mount paths. No../traversal. No absolute host paths — only paths the parent itself can access. - Resources: Child resource requests are checked against the parent's remaining budget
- Secrets: Children can only receive secrets that the parent explicitly has access to. The bridge validates this.
- Network mode: Children inherit parent's network mode or more restrictive
The bridge enforces this by intercepting the jcard.toml before forwarding to mb up.
This is not optional — the demo's security narrative is meaningless without it.
Approach: Guest-side nftables managed by stereosd
# Applied by stereosd at boot, before agentd starts
nft add table inet stereos_egress
nft add chain inet stereos_egress output { type filter hook output priority 0 \; policy drop \; }
nft add rule inet stereos_egress output ct state established,related accept
nft add rule inet stereos_egress output ip daddr 10.0.2.2 accept # host gateway (for vsock)
nft add rule inet stereos_egress output udp dport 53 accept # DNS resolution
# For each allowed domain, resolve and add:
nft add rule inet stereos_egress output ip daddr <resolved_ip> accept
Considerations:
- Domain-based rules require periodic DNS re-resolution (IPs change)
- Alternative: Use a forward proxy (squid/envoy) on the host with domain-based ACLs, guest routes all traffic through it
- The proxy approach is more robust for domain-based filtering but adds complexity
- Strict JSON-RPC schema validation — reject malformed messages
- Rate limiting on the bridge (max N requests/second)
- Command allowlist: only
up,list,status,destroy,down,ssh— noserve,vmhost,pull - Request size limits (prevent oversized jcard.toml payloads)
- Timeout on all bridge operations
Every command through the vsock bridge is logged:
{
"timestamp": "2026-02-28T10:15:33Z",
"source_vm": "orchestrator",
"command": "up",
"target": "auth-agent",
"config_hash": "sha256:abc123...",
"result": "allowed",
"reason": ""
}- Logged to
~/.mb/audit.log - Enables post-hoc review of what any orchestrator did
- Could feed into
ORCHESTRATION_REPORT.mdgeneration
| Item | Description | Complexity |
|---|---|---|
| Egress enforcement | nftables rules in stereosd, applied before agentd starts | High |
--config flag on mb up |
Accept alternate jcard.toml path | Low |
completed/failed states |
Agentd exit → stereosd → vsock → host state machine | Medium |
Why first: Egress enforcement is a prerequisite for any multi-agent pattern. Without it, the isolation story is broken. The completed state is needed for monitoring.
| Item | Description | Complexity |
|---|---|---|
| Vsock API bridge | Host-side bridge proxying commands from guest to daemon | High |
mb-proxy guest binary |
Guest-side CLI that talks to bridge over vsock | Medium |
| Parent-child tracking | spawned_by, spawn_depth in sandbox state |
Medium |
[orchestration] config section |
Resource quotas, max_children, max_depth | Medium |
| Config privilege ceiling | Bridge validates child config ≤ parent privileges | Medium |
Why second: This is the core capability. Requires Phase 1's egress enforcement to be safe.
| Item | Description | Complexity |
|---|---|---|
mb list uptime + restarts |
Surface agentd metrics over vsock health channel | Medium |
mb list --tree |
Hierarchical display of parent/child VMs | Low |
mb destroy --cascade |
Destroy VM and all descendants | Medium |
| Audit logging | Log all bridge commands to ~/.mb/audit.log |
Low |
| Scope isolation | Bridge filters list/ssh/destroy to own children only | Medium |
| Item | Description | Complexity |
|---|---|---|
| Rate limiting on bridge | Prevent DoS via rapid command spam | Low |
| DNS-aware egress (proxy approach) | Replace static IP rules with domain-aware proxy | High |
| Bridge schema validation | Strict RPC validation, size limits | Low |
| Integration tests | End-to-end orchestrator spawning children | Medium |
-
Should
mbinside a VM be opt-in? The[orchestration]section could default toenabled = false, requiring explicit opt-in. This prevents accidental exposure of the vsock bridge. -
Proxy vs nftables for egress? nftables is simpler but brittle for domain-based rules (IP changes). A host-side proxy is more robust but adds latency and complexity.
-
Max nesting depth? The demo shows depth=1 (orchestrator → children). Should we support depth=2+ (children spawning grandchildren)? Recommend starting with max_depth=1 and expanding later.
-
Secret inheritance model? Should children automatically inherit parent secrets, or require explicit pass-through? Explicit is safer.
-
What happens when orchestrator is destroyed but children are still running? Options: (a) cascade destroy all children, (b) orphan children and let them finish, (c) configurable behavior.
Do not ship the orchestration pattern without egress enforcement and scope isolation. The combination of "agent can spawn VMs" + "no network restrictions" + "no scope boundaries" creates an unacceptable attack surface.
Minimum viable secure orchestration requires:
- Enforced egress allowlists (Phase 1)
- Scope-isolated bridge (children only) (Phase 2)
- Config privilege ceiling (children ≤ parent) (Phase 2)
- Resource quotas with max_children/max_depth (Phase 2)
Without all four, an agent that's been prompt-injected or goes off-rails can exhaust host resources, exfiltrate data, or destroy other workloads.
agent-orchestrator-demo/index.html— Interactive demo showcasing the patternmasterblaster/pkg/config/config.go— jcard.toml parsing and validationmasterblaster/pkg/daemon/sandbox.go— VM lifecycle state machinemasterblaster/pkg/vsock/— Vsock protocol (health, mounts, secrets, shutdown)masterblaster/cmd/— CLI command implementations