# VM isolation

> How Skipbox keeps jobs apart: one new VM per job, deleted with its disk, a runner for one job, no inbound connections, and private repositories only.

## One new VM per job

Every job gets a new VM, made for it. The VM runs that one job and is never given another, then it's deleted with its disk. A VM still there 6 hours after it started is deleted too.

Nothing a job leaves on disk, in Docker or in memory reaches a later job.

## Where the VMs run

In Helsinki, on dedicated servers Fluxenic rents from Hetzner and on Hetzner Cloud servers made for one job each. A Hetzner Cloud server's vCPU are shared with other Hetzner customers; no other job shares that server, its network or its disk.

## A runner for one job

Skipbox registers each runner just in time, for a single job, with the job's own labels. On an organization it's in the organization's default runner group; on a personal account it's on the job's repository, so it can only run that repository's jobs. A runner left registered after the job is removed.

## No inbound connections

Nothing on the internet can connect to a job's VM. See [Network and egress](https://docs.skipbox.dev/network).

## Private repositories only

On a public repository, anyone who opens a pull request can run code on a self-hosted runner. Skipbox refuses jobs from public repositories and emails the owner. A repository made public later has its waiting jobs refused.

## What a job can read

A job's VM holds your workflow's secrets and GitHub's token for that job, as on any runner, and code the job runs can read them. Treat a Skipbox runner as you treat a GitHub-hosted one: give a job only the secrets it needs.

Updated 2026-11-09 · https://docs.skipbox.dev/isolation
