Every pull request Codeward reviews is, definitionally, code we've never seen before, from a repository we don't own, that we sometimes need to partially execute in order to understand what it actually does. That's not a hypothetical security concern — it's the literal job description. A code review platform that can't safely run untrusted code isn't a code review platform; it's a very confident guesser.
Why containers weren't enough
Our first instinct, like most infrastructure teams, was containers. They're fast to spin up, well-tooled, and familiar. But containers share a kernel with the host by default, and the isolation boundary between a container and the host is a matter of configuration discipline, not physical hardware separation.
For scanning arbitrary, potentially adversarial code from the public internet, "isolation that depends on getting every configuration flag right" is not a bar we were comfortable with.
Firecracker microVMs (via Fly.io) give us a meaningfully different guarantee: each sandbox is a genuine virtual machine with its own kernel, using KVM-based hardware virtualization for isolation rather than shared-kernel namespacing. The blast radius of anything malicious inside a sandbox is bounded by actual hardware virtualization boundaries, not by careful seccomp profiles.
Ephemeral by default, not by discipline
Every sandbox is created fresh for a single scan and torn down immediately after. There is no persistent sandbox pool that gets reused across PRs — the tradeoff of slightly higher cold-start cost is worth it for the property that no scan can ever inherit leftover state, files, or environment variables from a previous, unrelated scan.
"Ephemeral" here isn't a policy we enforce through cleanup cron jobs; it's the default architectural lifecycle of the system.
The guard clauses that actually matter
Isolation infrastructure is only as good as its weakest entry point, and for us that entry point is sandbox creation itself. We recently shipped dual guard clauses — one in the main createSandbox() function and a matching one in the LocalExecSandbox constructor used in local/dev execution paths — specifically closing a gap that could otherwise have allowed a maliciously crafted PR to achieve remote code execution against the orchestrating host rather than staying contained inside its sandbox.
We shipped that fix in its own isolated pull request, deliberately not bundled with any other change. Security-boundary fixes get reviewed and merged on their own, because the entire point of the fix is to be auditable in isolation.
Isolation at the agent level, not just the PR level
Because each specialized agent (security, bloat, architecture, and others) runs its own analysis pass, isolation happens at the level of each agent's execution, not just once per PR.
This means a compromised or adversarial code path that somehow affects one agent's sandbox doesn't have a path to affect a sibling agent's sandbox running the same PR — they're fully independent microVMs, not threads or processes sharing an environment.
The honest tradeoff
Hardware-level VM isolation costs more in cold-start latency than a shared-kernel container would. We've accepted that tradeoff deliberately: a few hundred milliseconds of extra startup time per scan is a cost we're willing to pay in exchange for an isolation boundary we don't have to keep re-auditing every time we change how the sandbox is configured.
Curious how PR scanning stays fast without cutting corners on isolation? Every Codeward scan runs in its own disposable Firecracker microVM — no exceptions, no shared state.