Releases: blox-eng/openblox
Releases · blox-eng/openblox
Release list
v0.8.1
v0.8.0
v0.7.0
v0.6.2
v0.6.1
v0.6.0
0.6.0 (2026-09-20)
Breaking Changes
* feat!: harden sandbox isolation, release pipeline, and docs for public release
Fixes five security weaknesses, tightens the release pipeline against
supply-chain tampering, and documents the trust boundary the project
actually enforces.
Security fixes:
- Preview proxy cross-sandbox response leak. preview.Handler pooled
upstream keep-alive connections under one shared host, so a request
authorised for one sandbox port could be served over an idle connection
to a different sandbox port. Every (sandbox, port) now has its own pool
and the dialler refuses an address outside the authorised route.
- Unbounded Exec output. A sandbox printing until its timeout could
exhaust the memory of the calling process, or of openbloxd, taking down
every sandbox it brokers. Output is now capped per stream at 16 MiB.
- Timed-out commands kept running. Exec stopped waiting but the command
and its children ran on inside the sandbox. The process group is now
killed with SIGKILL.
- Root was not refused. WithUser documented that root was forbidden but
did not enforce it.
- Swap doubled the memory bound. Sandboxes are created with MemorySwap
equal to Memory.
Release pipeline: the vulnerability gate now fails closed, the release
workflow no longer runs an unpinned third-party binary with the release
token, refuses workflow_run events originating from pull requests, and
tags exactly the commit CI verified. Published image versions can no
longer be overwritten. Binaries and the sandbox image carry Sigstore
build provenance and a CycloneDX SBOM.
Also adds an adversarial integration suite (network, filesystem,
privilege, process and timeout, output flooding, cross-sandbox
isolation, crash recovery, daemon restart, client disconnect, leak
check), runs the gVisor suites on arm64, and adds THREAT_MODEL.md and
RELEASING.md.
BREAKING CHANGE: WithUser and the openbloxd profile `user` now accept
only an explicit, numeric, non-zero uid:gid. Root (0:0), group 0, user
names and a bare uid ("1000") are refused: Create returns ErrInvalid and
openbloxd refuses to load such a config. A name is refused because the
untrusted image resolves it and can map it to uid 0; a bare uid because
Docker then takes its groups from that image's /etc/passwd and
/etc/group, which can include group 0. The default, 1000:1000, is
unaffected.
Exec now keeps at most sandbox.MaxOutputBytes (16 MiB) of each of stdout
and stderr; output past that is discarded and Result.Truncated is set.
Read large results with ReadFile, which streams.
Create on a stopped sandbox now replaces it with a fresh one under the
options of that call, rather than returning it still stopped.
Cancelling an Exec context now returns the context's error rather than
ErrTimeout.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* fix: close review gaps in containment, the kill path, and the publish guards
From review of the hardening pass. Each was verified against the code
before being fixed.
- Spec.Validate refuses an EgressPolicy that is neither EgressNone nor
EgressUnrestricted. Backends attach a network interface to anything
that is not EgressNone, so an unchecked value resolved to the
permissive answer.
- killGroup waits briefly for the group record instead of giving up when
it is absent. A command cancelled between the runtime starting it and
its wrapper's first statement had no record to be killed by and ran on
— the case a client that disconnects as soon as it has asked is most
likely to produce. killScript now reports "no record yet" distinctly
from "nothing to kill", and removes the record only once it has read
it, so a concurrent write is never unlinked from under the wrapper.
- Backend.halted returns its inspection error rather than reporting a
container it could not inspect as running. Create returned a stale
sandbox when the daemon was unreachable, or when the sandbox was
removed between being opened and being checked; a vanished sandbox is
now replaced.
- publish-image refuses to overwrite a published version unless the
registry itself said the version is absent. imagetools inspect fails
the same way for a missing manifest and for a network, registry or
auth fault, and reading the latter as "absent" would overwrite exactly
what the guard protects.
- The post-publish verify job holds attestations: read, which its own
gh attestation verify needs. Without it the check fails after the
assets are public.
- The SBOM step clears GOARCH with env -u rather than an assignment
prefix, which reads as the mistake shellcheck takes it for.
- docs/image.md's example contract assertion checks test, which the
stated contract requires and ReadFile execs as an external program.
Tests: the kill-path regression is covered by a test that stages a live
exec whose group record appears late; it fails without the fix. Egress
validation is covered by a table test.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>