Sandfort
Open source · Apache-2.0

A clean machine for untrusted work.

Sandfort is a native macOS app that builds disposable Linux virtual machines in UTM. Run the take-home challenge, the unvetted dependency, or the sketchy repository inside one — then throw it away and start clean in seconds.

macOS 13+ Apple silicon Runs on UTM Ubuntu · Fedora · Debian · openSUSE
Sandfort app icon: a sandbox holding a sandcastle with a shield

Why it exists

Some code should never touch your real machine.

A recruiter sends a coding challenge. A tutorial says to pipe a script into your shell. A dependency you have never heard of wants a post-install hook.

Each of those runs with your files, your SSH keys, your browser profile, and your password manager sitting right there. Attackers know it — Elastic Security Labs documented a campaign that delivered malware through fake interview challenges, which is part of what prompted this project.

Sandfort's answer is boring on purpose: give that work a whole separate computer, make the separate computer cheap to create, and make throwing it away the normal thing to do rather than a chore.

How it works

Build once. Reset forever.

Sandfort provisions one trusted protected baseline per distribution, then stamps out numbered disposable instances from it. Resetting an instance restores its disk and firmware state from that baseline — it does not clean up a dirty machine, it replaces it.

Protected Baseline verified image never run directly Instance 1 offline · own disk, UUID, MAC Instance 2 internet enabled by choice Instance 3 runs concurrently Reset & Run Clean disk + UEFI restored from the baseline
One baseline per distribution. Instances are independent, numbered, and disposable.

Create the baseline

Sandfort downloads the distribution's official ARM64 cloud image, verifies its pinned SHA-256, and provisions it with cloud-init: desktop, firewall, guest tools, security updates, and the development tools you picked.

Work in an instance

Every clean sandbox is a full independent copy with its own disk, UEFI state, VM UUID, and MAC address. Open the untrusted thing there. Instances run side by side, and offline is the default.

Reset or delete

Reset & Run Clean restores that instance from the baseline. Resume deliberately keeps its state — and its contamination. Deleting moves the bundle to the Trash, and numbers are never reused.

Curated guests

Four distributions, each actually booted and verified.

The catalog is deliberately small. A profile ships only after its official image, pinned checksum, ARM64 boot behaviour, desktop, firewall, and completion checks are tested end to end on real hardware — not just configured and hoped for.

Default profile

Ubuntu 24.04 LTS

  • UFW firewall
  • unattended-upgrades
  • GNOME desktop
  • Signature-verified checksum
Cloud edition

Fedora Cloud 44

  • firewalld + SELinux enforcing
  • Security-only DNF5 updates
  • Workstation desktop
  • Signature-verified checksum
Trixie

Debian 13

  • UFW + AppArmor
  • unattended-upgrades
  • GNOME / GDM
  • Hash-verified checksum
Leap

openSUSE Leap 16.0

  • firewalld + SELinux enforcing
  • Daily security patch timer
  • GNOME + Firefox + terminal
  • Signature-verified checksum
4 GB RAM 4 vCPU 64 GiB disk Git · curl · jq always installed Python 3 and Node.js LTS optional VS Code on by default

Isolation

What is actually enforced — and what is not.

A sandbox that overstates itself is worse than no sandbox, because you trust it with things you shouldn't. So here is the honest version of both halves.

Enforced The app guarantees this

  • Offline by default. Clean instances start isolated from both the host and the Internet. Outbound access is an explicit, per-launch choice.
  • No shared surfaces. No shared folders, no synchronized clipboard, no automatic USB passthrough, no bridged networking, no inbound port forwarding.
  • Verified images only. Official immutable cloud images with pinned SHA-256 values. A mismatch is never silently accepted.
  • Signed checksums. Ubuntu, Fedora, and openSUSE checksums are verified against the distribution's OpenPGP signature using bundled, fingerprint-pinned keys.
  • Hardened guests. SSH disabled, unsolicited inbound traffic denied, security updates enabled, SELinux or AppArmor active.
  • Local credentials. The guest password is generated on your Mac and shown in the app. No telemetry, no secret collection, nothing transmitted.
  • Native everything. Download, hashing, QCOW2 work, ISO creation, and launch all happen through Swift APIs — no bundled shell scripts, osascript, or UI automation.
  • It does automate UTM. Sandfort asks UTM to start, replace, and remove its own virtual machines, using Apple Events sent directly from Swift rather than a scripting layer. macOS asks your permission the first time, and starting a sandbox needs it — decline and Sandfort still builds the VM, but you start it yourself from UTM.

Residual risk A VM is not a perfect boundary

  • Escapes are possible. A vulnerability in the guest OS, QEMU, UTM, or macOS can break the boundary. Keep all of them updated.
  • Internet mode is real Internet. Connected malware can reach external services, exfiltrate what it finds, and attack other systems.
  • Anything you type is exposed. Whatever goes into the guest is available to whatever is running in the guest.
  • Resume keeps contamination. Only Reset & Run Clean restores from the baseline; resuming an instance deliberately preserves its state.
  • Offline is not audited. A host-side monitor cannot observe connections that UTM blocks, so "no observed traffic" is never proof that nothing was attempted.

Never put anything you care about in a sandbox

No personal accounts, SSH keys, cloud credentials, password managers, wallets, work files, or secrets. Sandfort reduces the blast radius of running untrusted code. It does not make running untrusted code safe, and it shows you this disclosure before you can create your first environment.

Details that matter

Signature verification in Swift

A minimal, bounds-checked OpenPGP verifier confirms that a pinned checksum is a value the distribution actually signed — with no dependency on the gpg tool and no key ever fetched at runtime.

Independent environments

Each distribution keeps its own baseline, credentials, tool configuration, and instance numbering. Verified downloads are shared; mutable disks and firmware never are.

Custom setup scripts

Advanced mode embeds your own shell script into cloud-init. It runs as root inside the guest during trusted baseline creation — never on your Mac.

A log you can hand to someone

Every line in the activity log carries a wall clock and elapsed time, so a slow step is visible and the log correlates with the guest's own setup output.

Memorable, measured passwords

Guest sign-in uses a four-word phrase drawn from a reviewed 2,048-word list. The entropy claim is written down, enforced by tests, and documented alongside its limits.

Ready for more platforms

Guest provisioning and host virtualization sit behind a deliberate provider boundary, so other hypervisors and hosts can be added without weakening the shared policy.

Get started

Build it and run your first sandbox.

Sandfort is source-first today. Clone the repository, build the app, and open it.

# 1. install UTM from https://mac.getutm.app

$ git clone https://github.com/shaztechio/sandfort.git
$ cd sandfort
$ make test
$ make app
$ open dist/Sandfort.app

Requires macOS 13 or later on Apple silicon, Xcode command line tools, and UTM. The app finds UTM wherever it is installed and offers to fetch it if it is missing.

  1. Read the disclosure. Sandfort shows what it does and does not protect before the first environment can be created.
  2. Add a Linux environment. Pick Ubuntu, Fedora, Debian, or openSUSE, choose your development tools, and start the build.
  3. Let setup finish. First boot runs in a text console because cloud images log to the serial port. It installs the desktop and tools, then powers itself off.
  4. Click Finish Setup. UTM labels the source VM Protected Baseline and creates Instance 1.
  5. Run a clean sandbox. Choose offline or Internet per launch, do the untrusted work, then reset it away.