Back to Blog
Architecture10 min read2026-07-09

gVisor Container Sandboxing Explained

How gVisor intercepts syscalls to put a user-space kernel between containers and the host, why it shrinks the attack surface, and the performance trade-offs you actually pay.

Ajay Kumar
Ajay Kumar
Founder & DevOps, PandaStack

The problem with shared kernels

Containers are not virtual machines. Every container on a host shares the *same Linux kernel*. That shared kernel is the security boundary — and it is a large, complicated boundary. Linux exposes roughly 350+ syscalls, and a vulnerability in any of them can be a path from inside a container to the host. CVEs like the runc container-escape bugs are the canonical examples: a bad interaction at the kernel boundary, and your isolation evaporates.

The traditional answer is defense in depth: seccomp profiles, dropped capabilities, user namespaces, AppArmor/SELinux. These help, but they are deny-lists and policy on top of the *same* kernel. gVisor takes a different approach — it puts a second kernel in the way.

What gVisor actually is

gVisor is an open-source application kernel from Google, written in Go, that implements a substantial portion of the Linux system call interface *in user space*. Instead of your container talking directly to the host kernel, it talks to gVisor, and gVisor decides what (if anything) reaches the host.

It has two main components:

  • Sentry — the user-space kernel. It intercepts application syscalls and implements them itself: memory management, a virtual filesystem, signal handling, and a full network stack (netstack). The Sentry itself runs heavily sandboxed and makes only a small, restricted set of host syscalls.
  • Gofer — a separate process that mediates filesystem access over the 9P protocol. The sandboxed application never gets direct host filesystem handles; the Gofer brokers them.

The result: the application sees a Linux-like environment, but the host kernel sees only a tiny, tightly-confined surface.

How syscalls get intercepted

gVisor supports two interception platforms:

PlatformMechanismNotes
ptraceTraps syscalls via ptraceWorks everywhere, higher overhead
KVMUses hardware virtualization to trapLower syscall overhead, needs KVM
systrapseccomp + signals (newer default)Faster than ptrace, no KVM needed

When the guest application issues a syscall, the platform redirects it into the Sentry. The Sentry handles it in Go code. If servicing it requires a host operation, the Sentry makes a *restricted* host syscall — and the Sentry's own seccomp filter caps that to a small allow-list. So even a compromised Sentry is boxed in.

Why this matters for security

The whole pitch is attack-surface reduction. A normal container exploit needs a bug in the host kernel reachable from the container. With gVisor:

  1. 1The application's syscalls hit the Sentry, not the host.
  2. 2Most syscalls are fully serviced in user space and never reach the host kernel at all.
  3. 3The handful that do reach the host go through the Sentry's own minimal seccomp filter.

An attacker now needs a bug in gVisor's Go implementation *and* a way through the Sentry's restricted host interface. That is a dramatically narrower path than "any kernel syscall bug." It is not magic — gVisor itself can have vulnerabilities — but it removes the host kernel as a single large target.

The trade-offs (be honest)

Nothing is free. gVisor adds a layer, and you pay for it:

  • Syscall-heavy workloads slow down. Each intercepted syscall costs more than a native one. Workloads dominated by I/O syscalls or fork/exec churn feel it most.
  • Some features are unimplemented. gVisor implements *most* of Linux but not all. Exotic syscalls, certain ioctls, and some /proc corners may be missing. Most web apps don't care; specialized software might.
  • Compatibility quirks. Things that poke directly at host kernel behavior (some monitoring agents, certain filesystem assumptions) can misbehave.

For typical stateless web services, CPU-bound app servers, and untrusted code execution, the overhead is usually acceptable and the isolation is well worth it. Google runs it in production for Cloud Run and App Engine, which is a strong signal for that class of workload.

A quick taste

If you have the runsc runtime installed, running a container under gVisor with Docker is a one-flag change:

# Register runsc with Docker (one-time)
sudo runsc install
sudo systemctl restart docker

# Run a container under gVisor instead of runc
docker run --runtime=runsc --rm -it alpine sh

Inside, prove you are on a different kernel:

# The kernel version string reflects gVisor, not the host
uname -a
# Linux ... 4.4.0 ... (gVisor reports its own version)

In Kubernetes, you wire it up with a RuntimeClass:

apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
  name: gvisor
handler: runsc
---
apiVersion: v1
kind: Pod
metadata:
  name: sandboxed
spec:
  runtimeClassName: gvisor
  containers:
    - name: app
      image: my-app:latest

Where this fits in a real platform

Multi-tenant platforms have a specific problem: running *other people's code* next to other people's code. A shared-kernel container is a weak boundary when you don't trust the workload. This is exactly why we run free-tier apps on PandaStack inside a gVisor sandbox — combined with spot/preemptible nodes and KEDA scale-to-zero. The gVisor layer means a hostile or buggy free-tier app has a much harder path to the host or to neighbors, while the platform keeps per-app costs low enough to give that tier away.

The trade-off we accept: a little syscall overhead and the scale-to-zero cold start on preemptible nodes. For dev/hobby workloads that's a fine deal; for production paid tiers you'd typically run on standard nodes.

When to reach for gVisor

  • You run untrusted or semi-trusted code (CI runners, user functions, multi-tenant apps).
  • You want stronger isolation than vanilla containers but lighter weight than full VMs.
  • Your workload is not pathologically syscall-bound.

If you control every workload and trust it fully, plain containers with good seccomp/AppArmor may be enough. If you need *hard* hardware-level isolation for adversarial workloads, microVMs (Firecracker, Kata) are the heavier alternative. gVisor sits deliberately in the middle.

References

  • [gVisor official documentation](https://gvisor.dev/docs/)
  • [gVisor architecture guide](https://gvisor.dev/docs/architecture_guide/)
  • [gVisor security model](https://gvisor.dev/docs/architecture_guide/security/)
  • [Kubernetes RuntimeClass docs](https://kubernetes.io/docs/concepts/containers/runtime-class/)
  • [Linux seccomp documentation](https://man7.org/linux/man-pages/man2/seccomp.2.html)

---

Want strong isolation without managing any of this yourself? PandaStack runs free-tier apps in a gVisor sandbox by default. Push a repo and it builds, deploys, and goes live — try the free tier at [dashboard.pandastack.io](https://dashboard.pandastack.io).

Ready to deploy?

Start free on PandaStack.

Start free on PandaStack

More in Architecture

Browse all Architecture articles →

See also