Security-research VMs for Apple silicon, built from verified vendor installers.
The ./rhubarbtart-tui dashboard, running inside herdr.
Describe a guest in a short JSON profile: an OS (macOS 26 or 27, NixOS or Kali) and the tools you need. RhubarbTart downloads the vendor installers and checks each one against a pinned hash and, where one exists, the vendor's signature. It then builds a hardened Tart VM image from them and tests a temporary copy from outside the VM. You work in disposable clones of the image, each with its own password, and delete them when you're done. In an engagement, the commands you run and the files you collect are kept as evidence on your Mac. You can seal that evidence into a signed vault to hand over.
Use it for security work where you need to know what was on the machine. Examples are testing macOS and iOS apps, analysing malware, client engagements, and AI agents working on scoped research under herdr. What it's for describes each use.
Research VMs are often built from a snapshot someone else made, then changed over time. After a while it's hard to say what software the machine contained. It's also hard to reproduce a result on the same setup, or to be sure that nothing from one job carried over into the next.
RhubarbTart is built to answer those questions:
| Verified inputs | Each guest starts from the OS vendor's own installer. Every download is pinned by its hash, checked against the vendor's signature where one exists, and checked again inside the guest before it's installed |
| Tested before use | A new image only gets its final name after a temporary copy of it passes a set of security checks run from outside the VM |
| Hardened defaults | No default passwords, no automatic login, no password-free sudo for users (one narrow Kali exception), SSH by key only or not at all, firewall on, and no machine or VPN identity shared between copies |
| Secrets on the host | Passwords are stored in your macOS keychain. Every copy gets its own password, and VPN sign-in happens per copy, never inside the image |
| Evidence you can hand over | In an engagement, the commands run through rhubarbtart exec and the files collected from clones are kept on your Mac in a hash-chained journal. Seal it into a signed vault that can be checked offline on any machine (Engagements) |
| Configured in JSON | A guest is defined by a short profile: an OS, a list of tools and a few options |
Every image records what went into it. The dashboard's Provenance tab shows the build commit,
the input and lock hashes, the pinned toolchain and the locked base.
There are four main parts:
Profile β Lock β Image β Clone
- A profile describes the guest you want: an OS and a list of tools.
- Resolving the profile produces a lock file. It lists the exact version, download URL and hash of every input (each installer and package). You review the lock and commit it, like code.
- Building installs everything the lock lists into a hardened image. The image is tested from the outside, then kept as a template and never started.
- You work in a clone of the image: a disposable copy with its own password. When you're done, delete the clone. The next clone starts from the same state.
An image's name comes from its inputs (rbt-<profile>-<hash>), so the same lock always gives
the same image name. The build saves a record of what went into each image in
out/<image>.provenance.json.
Tip
New to the terms? Key concepts explains each one, including the build steps (vanilla VM, seal, smoke test, provenance) and optional features such as stacked clones.
Each use follows the same steps: build a hardened guest with known contents, work in a disposable clone, and delete the clone afterwards.
macOS and iOS app testing
Testing a macOS app, an iOS app and its backend, or an Apple service needs a clean Apple environment, set up the same way each time. RhubarbTart builds a hardened macOS guest with your tools (Chrome, ZAP, a VPN or ZTNA client) pinned and verified. Each image's contents are recorded, and each clone is separate and disposable. So you can state what the machine contained, repeat a test from the same starting point, and keep one client's data out of the next engagement.
It isn't an iOS VM: Tart runs macOS and Linux guests. For iOS apps, RhubarbTart covers backend testing and inspecting app bundles today. Xcode and the iOS Simulator are not part of it yet.
Why Apple app testing is hard, what each part of the tool does about it, and Apple's limits for iOS work: Testing macOS and iOS apps.
Disposable machines for research and malware analysis
Running a malware sample or examining something hostile calls for a machine you can trust before the run and throw away after it. Clone the image, do the work in the clone, then delete it. The image itself is never started, so it can't be infected, and the next analysis starts from the same clean state. Because the image's contents are recorded, anything you find that wasn't in the image came from the sample, not from leftover tools.
NixOS and Kali give you a fully pinned Linux machine for analysis. macOS guests let you study Mac malware on the platform it targets. Clones can't reach each other. An engagement can open an explicit link between two of them, and a lab target like Juice Shop has no route out (Engagements).
Agent-driven engagements with herdr
RhubarbTart can run AI agents for scoped research, penetration tests and CTFs inside these VMs. The agents run under herdr, a terminal workspace manager for AI coding agents. Evidence stays on the host, outside the VMs. You can:
- create and remove a whole set of clones for one scope as an engagement;
- record the commands run in its clones and the files they produce as hash-chained evidence, and seal that evidence into a signed, portable vault;
- start the engagement's agents under herdr with
rhubarbtart herdr arm. Each agent reaches only its assigned clone, through therbt-rangeclient. Commands that match a configured pattern wait for your approval.
Not built yet: enforcing an engagement's agent budget, recording the agents' prompts and replies,
and running each engagement's agents in their own VM instead of on your Mac. The
herdr charter sets the boundary for this work, and
docs/PLAN.md has the design and roadmap.
On an Apple silicon Mac running macOS 26 or later. kali-research and nixos-research also need
Rosetta; if it isn't installed, run softwareupdate --install-rosetta --agree-to-license first.
Kali needs about 25 GB of free disk space (Disk space).
# 1. Install the pinned tools into ./.toolchain (no Homebrew, no sudo)
./tools/bootstrap.sh && source scripts/env.sh && uv run tools/resolve.py preflight
# 2. Optional: refresh the guest's inputs to their newest versions, then review the changes.
# Skip this to build exactly what the repository pins.
# uv run tools/resolve.py resolve kali-research && git diff locks/
# 3. Create an SSH key for your VMs (first time only; set a passphrase when asked),
# keep its passphrase in your keychain, then build and test the image
[ -f ~/.ssh/rhubarbtart_ed25519 ] || ssh-keygen -t ed25519 -a 100 -C rhubarbtart -f ~/.ssh/rhubarbtart_ed25519
ssh-add --apple-use-keychain ~/.ssh/rhubarbtart_ed25519
RHUBARB_SSH_PUBKEYS=~/.ssh/rhubarbtart_ed25519.pub ./scripts/build.sh kali-research
# 4. Make a clone and start it; don't use the image directly
./rhubarbtart new web-1 --profile kali-research && ./rhubarbtart run web-1What each step does
-
Bootstrap downloads Tart, Packer and its Tart plugin, uv, zot and cosign, and builds GnuPG from source. Each is checked against a pinned hash and installed into the repository's own
.toolchain/folder.preflightthen confirms that these are the versions on yourPATH. Building GnuPG needs the Xcode Command Line Tools. -
Resolve is optional. The included profiles have committed locks, and the build downloads and verifies exactly those versions. Resolve looks up the newest versions instead, verifies them and rewrites
locks/kali-research.lock.json, which changes the image's name and leaves your checkout modified. Run it when you want newer versions, or when the build reports that a pinned download is gone (vendors such as Google keep only recent releases). -
Your SSH key gets you into your VMs. Use a key only for them, not the one you use for GitHub or servers. The first line creates it only if it doesn't exist yet.
ssh-add --apple-use-keychainloads it and stores its passphrase in your macOS keychain; after a restart, runssh-add --apple-load-keychainto load it again without typing the passphrase. The public key is built into the image, so a new key means rebuilding your images. Hardware security keys and other options: Your SSH key. Without a key, the image is built with SSH turned off.Build installs the OS from the vendor's installer, adds the tools, and seals the guest: it applies the hardening and checks that each setting took effect. It then starts a temporary copy and tests it from the outside. Only if those tests pass does the image get its final name. A build is a full OS install, so run it in a separate terminal. On an M1 Mac with 8 GB of memory, Kali took about 20 minutes and NixOS under 10. The first macOS build of each version took about 25, plus the download of its 18 to 25 GB restore image.
./scripts/build.sh --listlists the available profiles. -
rhubarbtart newcreates a clone and gives it its own password, stored in your keychain.rhubarbtart runstarts it in a window and keeps the terminal until the VM shuts down; add--detachto get the terminal back. Using your VMs coversssh,enroll,reset,rmand the dashboard.
./rhubarbtart-tui gives the same actions in a keyboard-driven dashboard, with tabs for images,
clones, provenance and logs. Inside herdr it uses herdr's colour theme.
| Profile | OS | Tools | Suited to |
|---|---|---|---|
tahoe-research |
macOS 26 | Chrome, ZAP, WARP, Tailscale | macOS app and client testing on any macOS 26 or newer host |
goldengate-research |
macOS 27 | Chrome, ZAP, WARP, Tailscale | The current macOS release; needs a macOS 27 host |
nixos-research |
NixOS 26.05 | Chrome, ZAP, WARP, Tailscale Β· XFCE Β· Rosetta | The most reproducible option: the whole OS is pinned to a single commit |
kali-research |
Kali rolling | Chrome, ZAP, WARP, Tailscale Β· kali-linux-default Β· XFCE Β· Rosetta |
Kali's standard set of security tools |
All guests are arm64, because Tart runs native guests on Apple silicon. Linux profiles with Rosetta enabled can still run x86_64 Linux programs. If none of these fit, you can define your own guest.
A fifth profile, juiceshop-target, is a lab target rather than a workstation: a NixOS guest that
runs OWASP Juice Shop on port 3000 with no route out. The juiceshop-lab engagement pairs it with
a Kali attacker (Engagements).
Which one should I pick?
%%{init: {'theme':'base','fontFamily':'ui-sans-serif, system-ui, -apple-system, Helvetica, Arial, sans-serif','themeVariables':{'primaryColor':'#ffffff','primaryTextColor':'#2b2d42','primaryBorderColor':'#c9184a','lineColor':'#8d99ae','edgeLabelBackground':'#ffffff','fontSize':'13px'},'flowchart':{'curve':'basis','nodeSpacing':45,'rankSpacing':55,'padding':8,'useMaxWidth':true}}}%%
flowchart TD
Q{"What are you<br/>testing?"}
Q -->|"macOS apps<br/>& clients"| H{"Host on<br/>macOS 27?"}
H -->|"yes"| GG["<b>goldengate-research</b><br/><i>macOS 27</i>"]
H -->|"no"| TH["<b>tahoe-research</b><br/><i>macOS 26</i>"]
Q -->|"Linux<br/>tooling"| P{"What matters<br/>most?"}
P -->|"Reproducibility<br/>& audit"| NX["<b>nixos-research</b><br/><i>NixOS 26.05</i>"]
P -->|"Largest<br/>toolset"| KL["<b>kali-research</b><br/><i>Kali rolling</i>"]
Q -->|"Something<br/>else"| OWN(["Define your<br/>own profile"])
classDef q fill:#fff0f3,stroke:#c9184a,stroke-width:1.5px,color:#2b2d42
classDef guest fill:#c9184a,stroke:#800f2f,stroke-width:1.5px,color:#ffffff
classDef own fill:#2b2d42,stroke:#2b2d42,color:#ffffff
class Q,H,P q
class GG,TH,NX,KL guest
class OWN own
The documentation is published as a searchable site at
errantpacket.github.io/RhubarbTart, built from
the docs/ folder. If you're new, start with the
Quick start and Key concepts.
Contributing: CONTRIBUTING.md. Reporting security issues:
SECURITY.md.
Open bugs, enhancements and the roadmap are in the issue tracker.
RhubarbTart is licensed under the Functional Source License 1.1, Apache-2.0 future
license (FSL-1.1-ALv2). You may use it for any purpose except building a competing
commercial product. Each release becomes Apache-2.0 two years after it is published. Third-party
components keep their own licenses, listed in THIRD-PARTY-NOTICES.md.