Security
Cubic is designed with three security goals in mind:
Protect the host from the guest. A virtual machine may run untrusted or even malicious software, so the guest must never be able to take control of the host it runs on.
Protect your virtual machines from other users of the same computer. One user should not be able to watch or control the virtual machines of another.
Protect your virtual machines from the network the host is connected to.
To meet these goals Cubic keeps the amount of trusted code small. It runs without a background service, it never asks for extra privileges, and it authenticates every connection that reaches a virtual machine.
No Privileged System Service
Many virtual machine managers rely on a background service that runs with system wide privileges. Cubic does not. Each time you run a cubic command it starts a short lived process that launches or stops a QEMU process owned by your own user account, and then it exits.
Because QEMU runs as your normal user with no extra rights, a guest that breaks out of its virtual machine cannot gain system wide privileges on the host. Any such escape stays inside your own user account, where the operating system keeps it isolated from other users in the usual way.
Verified Distribution Images
Cubic only uses official images that come straight from each distribution.
Before an image is used, Cubic compares it against the checksum that the distro
publishes next to it, using either SHA256 or SHA512. If the value does not
match, Cubic rejects the download and stops with an InvalidChecksum error.
This guards against downloads that are corrupted or altered on the way to your machine. The verified image is cached and shared by every virtual machine of the same distribution and version, so it is fetched and checked once. See File Locations for the cache directory of each platform.
Bound to Localhost
Every service that Cubic opens for a virtual machine, including the SSH port,
the QEMU monitor, and the serial console, listens only on the loopback address
127.0.0.1. None of them are reachable from the local network or from the
internet.
This already protects your virtual machines from outside attackers. A remote computer cannot connect to a service that listens only on loopback, so a virtual machine started with Cubic is never exposed to the network just by running.
Loopback can still be reached by other people who are logged in to the same
computer. Binding to 127.0.0.1 therefore keeps virtual machines off the
network, but on its own it does not separate one local user from another. That
separation comes from the authentication on each connection, which the sections
below describe.
Binding to loopback says nothing about the other direction. A guest still
reaches the internet by default, so it can install packages, and --isolate
cuts that off for workloads that must stay contained. Networking explains
both directions.
Port Forwarding
Cubic can forward a port from the guest to the host so that a service
running inside the guest becomes reachable from the host. You describe a forward
as host_port:guest_port, for example 8000:80, and you can put a host
address in front of it to choose where the port listens.
This choice matters. When you leave the address out, Cubic binds the forwarded
port to 127.0.0.1, so the service stays on loopback and keeps the protection
described above. When you set the address to 0.0.0.0 or to a public address
of the host, the service inside the guest becomes reachable from the local
network and possibly from the internet.
Only expose a port beyond loopback when you really mean to, and make sure the
service behind it is meant to be public and is properly secured. A port opened
on 0.0.0.0 gives an outside attacker a direct path into the guest.
SSH Access
For each new virtual machine Cubic creates a unique Ed25519 SSH key using the operating system’s secure random generator. The matching public key is placed inside the guest during first boot, and the private key stays on the host together with the virtual machine. You connect over the loopback port that belongs to that machine.
The intended way to reach a guest is SSH key authentication, which depends on holding the private key that Cubic stores alongside the virtual machine rather than on a password that could be guessed or shared.
A new machine has no account password at all. The user account is created with a locked password, so the SSH key is the only way in.
This shapes how you use the serial console. The console shows the login prompt of the guest, and that prompt accepts only a password, so it stays closed until you set one from an SSH session. Set a password while SSH works if you want the console available as a way in later. See Use the Serial Console for the steps.
Cubic also remembers the host key of each guest. The first connection stores the
key the guest presents in the machine’s instance.toml file, and every later
connection compares against it, the same idea as a known hosts file kept per
machine.
A key that does not match stops the connection. Cubic shows both fingerprints, points out that this may be a malicious attempt to take over the connection, and asks whether to trust the new key. Answering yes stores it, which is how you carry on after you recreated the guest yourself.
Encrypted QEMU Control Channels
The QEMU monitor and the serial console talk to Cubic over loopback connections that are protected with mutual TLS. Both ends have to present a valid certificate before any data flows, and the traffic itself is encrypted.
The first time a virtual machine starts, Cubic creates a small certificate authority just for that machine and uses it to issue a server certificate for QEMU and a client certificate for Cubic. These are stored with the machine and reused on later starts. Cubic uses rustls to load its own certificate and to check the one that QEMU presents.
This is what stops another user on the same computer from driving your virtual machine’s monitor or console. Even though they can reach the loopback port, they cannot complete the secure handshake without the client certificate that belongs to your machine.
Keeping Instances Apart
Everything that belongs to a virtual machine, including its SSH private key, its TLS certificates, its disk images and its cloud-init seed image, is stored under your own data directory, which File Locations names for each platform. Reaching a running machine means holding the SSH key or the TLS client certificate that is kept inside it.
What Cubic Does Not Protect Against
The goals above draw a line around what Cubic defends. These things sit outside it, and knowing that is part of using it safely.
Anything running as you. The protection is between user accounts, not inside one. Any process of your own user can read the SSH private key, the TLS client certificate and the disk image of every virtual machine you own, and can therefore reach every guest you can reach.
A port you publish yourself. A forward bound to 0.0.0.0 or to a public
address of the host puts the service inside the guest on the network, with
whatever authentication that service brings and no more.
Data at rest. Disk images, snapshots, SSH keys and certificates are stored as plain files. Anyone who can read your data directory, including a backup that leaves the machine, gets the contents of every VM instance. Use encryption on the host if that matters.
A mirror that serves a matching checksum. Verification proves the image matches the checksum the distribution published next to it. It does not prove that either file came from the distribution. Verifying a distribution signature over the checksum file would, and would remove the need to trust the connection to the mirror at all. Cubic does not do that yet.
A network cut with ``–isolate``. Isolation stops guest traffic. It is a containment feature rather than a boundary against a guest that has already broken out of QEMU.
Security Issues
If you believe you have found a security problem in Cubic, please report it
privately as described in the SECURITY.md file.