Skip to content
Polycentric-LabsPublic

About

Risk-tiered, host-verified-sealed Hyper-V sandbox VM provisioner (PowerShell). Run untrusted code or agents in tiered isolation behind a fail-closed seal gate.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

Voidseal

A Claude-Code-native, Windows/Hyper-V, local high-assurance execution harness for running untrusted code, untrusted AI agents, and (eventually) malware without exposing your host — built around the one thing nobody else ships: an unskippable, host-verified, fail-closed seal gate that proves the VM is starved of network, credentials, and host↔guest channels before any untrusted workload is allowed to run.

It's the risk-tiered, seal-verified version of the "bring your own VM" that Anthropic's own Claude Code security docs recommend for untrusted work — so it complements Claude Code's built-in (process-level) sandbox rather than duplicating it.

Important

Honesty up front (read this before you trust it with anything dangerous).

  • The Tier-0 disk round-trip is live-proven; the full multi-tier acceptance is not. The whole engine is mock-proven (1654 Pester tests (1652 passed, 2 skipped) plus 194 pytest tests against a fake Hyper-V backend), and the Tier-0 firefox disk-mode round-trip has run end-to-end on real Hyper-V: provision, host-verified seal, disk-passing workload, host-read result, clean teardown. Milestone 3 (2026-06-25) proved it with the legacy exFAT OUTPUT disk, and the current user-space outbox transport passed the same round trip on 2026-07-21 with a guest-produced result from the synthetic sample. Later changes are mock-tested only. The Tier-1 ralph live run is still pending, and no tier above 0 has had a live acceptance yet (operator-run, elevated — see docs/live-smoke-test.md).
  • Tier 2 and Tier 3 (disposable no-net / air-gapped detonation) are scaffold-only. The cold-VHDX→quarantine extraction sink throws NotImplemented in v1. Do not run live malware or untrusted-plugin detonation yet.
  • Windows + Hyper-V only, today. The "Tier-0 container" substrate is design-intent; v1 provisions Tier 0 as a Hyper-V VM whose seal removes its only network adapter, host-verified by the gate.
  • Tier-1 egress is host-enforced by design (EgressMode='HostProxy', what tier1.psd1 ships) and gate-verified, but mock-green only: it has never run live. The guest has no route, NAT or resolver; a host CONNECT allowlist proxy on the VM's own /30 is the only way out, behind host firewall rules and a port ACL that the seal gate reads back. Do not run a hostile workload at Tier 1 until the live checks in docs/phase-6-live-runbook.md section 2 pass. It is the one egress model for a VM that keeps its NIC, in Serial and Disk mode alike, and the builder runs on it too (see the Egress note in docs/tier-reference.md).
  • A profile's Mounts block does not deliver anything into the guest, and neither does StageAssets. Nothing in the Provisioner or Runner attaches a host-guest bind mount; the backend has no 9p, virtiofs or SMB method, so Mounts is validated (its source keys are secret-path-screened) and otherwise inert. A StageAssets ISO is attached before the seal and ejected by it before the guest's only boot. Files reach a running workload only through Disk-mode Inputs (the INPUT data disk) or DataDisks (pre-built, hash-verified disks the guest mounts read-only; build one with scripts/New-VoidsealDataDisk.ps1); the cloud-init seed is built from the profile and carries none of yours. Both work on a Tier-1 HostProxy VM as well as offline: a Disk-mode run on a kept-NIC VM gets the proxy settings, the in-guest lockdown and a static network-config in its seed. See Gap 2 in docs/live-smoke-test.md.
  • On the Invoke-Voidseal path, BlockProtocols is declarative and EgressAllowlist is enforced on the host for a Tier-1 run in either mode. No code reads BlockProtocols (HostProxy blocks UDP and non-443 traffic by construction anyway). EgressAllowlist is validated, merged and deduped; with EgressMode='HostProxy' (what tier1.psd1 ships, so ralph uses it) it is the list the host CONNECT proxy enforces, behind host firewall rules and a port ACL that the seal gate verifies, and the guest has no route, NAT or resolver of its own. This is mock-green and has never run live. The in-guest default-DROP in the seed is defense in depth only.

What it is

Voidseal provisions a risk-tiered sandbox VM, injects what a task needs, seals it to the required isolation, runs the workload, captures results across a one-way boundary, and always tears down (teardown runs in a finally — a failure leaves no orphan). The lifecycle is an explicit state machine: INIT → PROVISIONED → STAGED → SEALED → RUNNING → CAPTURED → EXTRACTED → DESTROYED.

Design north star: supervise capability, not behavior — assume the thing inside is a prompt-injectable insider, and make the blast radius structurally small.

The tiers

Tier Boundary Network Credentials Use
0 lightweight / offline (no-NIC VM in v1) none: the VM seals with no adapter (HostProxy is implemented for Tier 1 and moot here) none trusted local workloads, file organizers
1 net-restricted Hyper-V VM Internal-switch isolation (seal-verified); host-enforced egress allowlist (HostProxy: host CONNECT proxy, host firewall rules and port ACL, gate-verified; mock-green, never run live) scoped, on-demand autonomous agent loops against a target repo
2 disposable, no NIC none (structurally starved) none (refused at load) untrusted code (scaffold-only in v1)
3 air-gapped + sinkhole none none malware detonation (scaffold-only in v1)

Tier ≥ 2 profiles are structurally refused at load if they declare any credential or egress, and the seal gate refuses a VM that must have no NIC (Tier 0, Tier ≥ 2, any processor) while it still has one, and refuses a passthrough device, a secret volume, or a residual transfer medium.

What makes it different

It's not novel as any single primitive — Qubes has security-tiered VMs, Cuckoo/CAPE detonate malware, Firecracker/Kata are microVMs, and air-gapped detonation is standard practice. Voidseal is distinctive as an integrated combination on a specific delivery surface:

  1. A risk-tier ladder in one tool — most sandbox tools expose a single fixed boundary; Voidseal escalates Tier 0 → 3 with one interface.
  2. A host-side, fail-closed seal verification before run — the host independently certifies the tier's isolation contract and refuses to run otherwise. The adapter-count certification covers every VM except a Tier-1 non-processor; at Tier 1 the host instead certifies exactly one NIC, on the VM's own purpose-built Internal switch. Media, disk and host-channel checks run at every tier. This is the part nobody else ships: runtime enforcement (gVisor/Kata) and agent health checks (Cuckoo/CAPE) are not the same as a pre-run, host-side proof that the box is starved.
  3. A no-live-channel disk-passing model — inputs/outputs ride attached data disks; the guest self-powers-off; the host classifies from an exit-code sentinel. Works identically even fully air-gapped.
  4. Windows/Hyper-V native (most untrusted-code tooling is Linux/KVM/cloud) and fully mockable (the whole engine is unit-tested without elevation).

vs. Claude Code's own sandbox

Claude Code's native sandbox is an OS-process boundary (Seatbelt/bubblewrap + a network proxy), macOS and Linux only, single-boundary — great as the cheap default for routine coding. Voidseal sits one rung above it: a hardware-VM guest boundary, a literal airgap, a host-verified seal, hostile-output quarantine, and root-in-guest without root-on-host. Use Claude Code's sandbox for normal workspace- contained work; reach for Voidseal when a process sandbox on your real host kernel isn't enough.

Quick start

Requirements: Windows 11 Pro (Hyper-V) is the tested host; Windows 10 Pro is untested. PowerShell 7, Pester 5; an elevated session (or Hyper-V Administrators membership) to actually provision; a Debian-12 golden .vhdx + a cloud-init seed (see guest-images/debian-12-cloud.md).

Check prerequisites first (a read-only, unelevated pass/fail table — Hyper-V eligibility is genuinely hard to self-check by reading docs):

pwsh scripts/Test-VoidsealPrereqs.ps1

Fetch the golden disk (downloads the pinned Debian genericcloud image, verifies its SHA-512, and converts it to the golden VHDX — Debian cloud images are unsigned, so the TLS-sourced pin is the trust root):

pwsh scripts/Get-VoidsealGoldenImage.ps1        # add -Plan first to preview the pinned URL + hash
# From the repo root, dot-source the engine, then run the Tier-0 example.
# firefox is a Disk-mode profile: populate -Workload.Inputs with the organizer script + a
# sample bookmark profile first (built from profiles/firefox.psd1's InputFiles), plus the guest
# helpers run_disk_workload.py and outbox.py. A run whose Inputs lack either helper is refused
# before anything is provisioned. See docs/live-smoke-test.md §4A for the walkthrough.
. .\scripts\Invoke-Voidseal.ps1
$report = Invoke-Voidseal -Tier 0 -Profile firefox `
    -ParentDiskPath <golden.vhdx> -Destination <out-dir> -Workload @{ Inputs = $inputs }

Verify it worked. Invoke-Voidseal returns a report object (it does not print progress). A clean run traverses the whole state machine, certifies the seal from the host, and tears down — expect:

$report.States              # INIT PROVISIONED STAGED SEALED RUNNING CAPTURED EXTRACTED DESTROYED
$report.SealVerdict         # True    — Assert-Sealed certified the VM (the workload runs ONLY if True)
$report.RunResult.Status    # Success
$report.RunResult.ExitCode  # 0       the entrypoint's own exit code, carried back through the outbox
$report.ExtractedArtifact   # <out-dir>\result.html  — a real, guest-generated Netscape-HTML file
$report.Error               # $null   on full success
$report.TeardownStatus      # OK (VM removed, created disks deleted)

That is the Tier-0 firefox disk round-trip success shape, live-proven on real Hyper-V with the current outbox transport on 2026-07-21 (Milestone 3, on 2026-06-25, proved the legacy exFAT path). If SealVerdict is False the run aborted before the workload ran (the seal gate refused); $report.Error says why, and the VM is still torn down. The full walkthrough — building $inputs and a failure-triage table — is in docs/live-smoke-test.md §4A.

If the entrypoint exits non-zero, RunResult.Status is WorkloadFailed, RunResult.ExitCode carries the code, and nothing is released (ExtractedArtifact stays empty). That is a workload failure, not a transport fault; before this the same run surfaced only as a missing result.html candidate.

See docs/operator-runbook.md for the full provision → run → teardown walk, docs/tier-reference.md for the per-tier containment rubric, and profiles/ for the worked example profiles (firefox = Tier-0 bookmark organizer, ralph = Tier-1 net-restricted agent loop, builder = Tier-1 dependency fetcher).

Author your own workload → docs/authoring-a-workload-profile.md (the profile field contract + a minimal skeleton to copy, profiles/example-skeleton.psd1).

Testing

The whole engine runs against a fake Hyper-V backend — no elevation, no real VM:

Invoke-Pester -Path tests

CI runs the same suite, followed by pytest, on pushes to main and on pull requests targeting main (.github/workflows/pester.yml). See CONTRIBUTING.md, especially the rule that the fake backend must match real Hyper-V behavior.

AI Assistance

This project was developed alongside AI platforms.

Details, including the tools used: docs/ai-assistance.md.

License

MIT © 2026 Allen Byrd

About

Risk-tiered, host-verified-sealed Hyper-V sandbox VM provisioner (PowerShell). Run untrusted code or agents in tiered isolation behind a fail-closed seal gate.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages