Skip to content
Attack vectors

Attack vectors

This page lists the common ways that code you didn’t write gets to run on a developer’s machine or gets data off it, and what devvm does about each one. devvm stops most of them on its own, and the habits close most of what’s left. Narrowed, not closed and Left to you are the one list of what devvm leaves open, and each entry links to the page that explains its mechanism.

How devvm handles each attack

The rest of this page sorts the attacks by how much of each one devvm stops:

BlockedThe attack can’t work, because what it’s after isn’t in the VM or the VM can’t reach it.
Kept inside the VMThe attacker’s code runs, but it runs in the VM, where it reaches only the project folder and what you gave the VM.
Narrowed, not closeddevvm closes part of the attack, and the entry says what’s still open.
Left to youdevvm doesn’t stop the attack, and the entry says what to do instead.

Some protections hold only on some network tiers or only on macOS, and each entry names its conditions. Everything here rests on the VM’s boundary. How devvm does each of these is in the security model.

Blocked

Credentials on this machine

  • SSH keys. Malware on a developer’s machine looks in ~/.ssh first, because a private key opens every server and repo that trusts it. A VM never mounts ~/.ssh or anything else from your home folder, so there’s no key in it to copy. Agent forwarding, which you turn on yourself, lets the VM use your keys but never copy them.
  • Cloud, cluster and registry logins. Worms that steal credentials collect ~/.aws, ~/.config/gcloud, ~/.azure, ~/.kube/config, ~/.docker/config.json and the npm publish token in ~/.npmrc. A VM mounts none of them, so a package that goes looking finds nothing. Secrets you keep in the project folder are a different case, which Left to you covers.
  • The Keychain, browsers and password managers. Stealers read saved passwords, cookies and login sessions from browser profiles and the Keychain. The VM has no browser profile of yours, and it can’t reach this machine’s Keychain.
  • Your coding agents’ history. Agent transcripts hold what you pasted into them, such as secrets and code from other projects. Your history never goes into a VM, and each VM’s own history stays in that VM (coding agents).
  • Secrets, on every tier. Every VM, an open one included, gets a placeholder instead of each secret, such as your GitHub token or Claude Code’s token, and the proxy on this machine puts the real value only into requests for that secret’s own hosts (secrets). A placeholder copied out of the VM is worthless elsewhere, because it ends in a random value of that VM’s own, and an open VM that sends a request around its proxy sends only the placeholder. Another VM or a program on this machine can’t spend the secret through the proxy either, because the proxy needs the VM’s own password. Codex and opencode logins and Claude Code’s MCP secrets work the same way, and devvm refreshes OAuth logins on this machine, so a VM never holds a refresh token.

Git running code on this machine

  • Git hooks and config, on macOS. A VM can write the project folder, so without protection it could add a hook such as .git/hooks/post-checkout, or set a command in .git/config: core.fsmonitor, core.hooksPath, core.sshCommand, core.pager, core.editor, a filter.* or diff.*.textconv driver, a credential.helper or a ! alias. Your next git command on this machine would run it. devvm locks hooks and config with a flag that even root in the VM can’t clear (.git protection). Linux hosts have no such flag, which Left to you covers.
  • The shell prompt. Many shell prompts and editors run git status as soon as you cd into a folder or open it, and git status runs core.fsmonitor. The lock covers that as well, so opening the folder runs nothing that the VM wrote into .git.
  • devvm’s own git commands. devvm runs git on this machine itself, for example to read your name and email for the VM, to check a --clone VM’s repo for uncommitted changes, and to fetch from the VM. A VM can write a repo that git on this machine reads, such as the project folder’s on Linux or a repo inside a folder it mounts, so devvm’s git runs none of the programs a repo’s config can name. It turns off the repo’s fsmonitor, its hooks, including those its config defines, and its filters, it never enters a submodule for git status, and it uses no transport but ssh, so git status, a fetch or a push of devvm’s runs nothing that the VM wrote into the repo. It ignores the git variables of the shell you run devvm in, such as GIT_DIR and GIT_CONFIG_GLOBAL, so it never works on another repo or config by mistake, and it never asks you anything (GIT_TERMINAL_PROMPT=0). Its fetches and pushes reach the VM with ssh in batch mode (-o BatchMode=yes), so the VM’s ssh server can’t ask you for a password. They always connect to that VM itself, whatever host the repo’s config sends them to, accept only the host key devvm pinned for it, and forward neither your agent nor any port.

Getting out over the network, on the allowlist and none tiers

  • Sending data to the attacker’s server. Most attacks end by sending what they stole to a server the attacker runs. A confined VM reaches only its proxy, and on the allowlist tier the proxy allows only the hosts on the VM’s allowlist, and on the none tier only its agents’ and secrets’ hosts. On the internet tier the proxy allows every public host, the attacker’s included, so this holds only for this machine and your networks. devvm leaves storage and paste sites out of the default allowlist on purpose, because they’re easy ways to send data out (allowlists).
  • DNS tunnelling. An attacker can encode data into names and look them up at a DNS server of their own. A VM sends no DNS queries of its own, because names resolve in the proxy on this machine.
  • Services on this machine and your network. Code in a VM could attack what developers leave open on localhost, such as databases, dev servers, Docker’s API and other VMs’ ports. It could also attack your router, a NAS, or a cloud provider’s metadata service at 169.254.169.254. The proxy refuses this machine’s own addresses and internal ones, such as loopback, private, link-local and CGNAT ranges, unless a rule names the address (the proxy).
  • DNS rebinding and address tricks. A name can resolve to a public address when it’s checked and to an internal one when it’s dialed, and an internal address can hide in an IPv6 or NAT64 form. The proxy dials only the address it checked, and it sees through NAT64 forms (the proxy).
  • Going around the proxy. Root in a VM can change its routes and firewall, but devvm confines the VM from outside it, so nothing in the VM reaches anything but the proxy (confinement). devvm catches a VM started outside devvm, or one given a second network, with the self-check. It stops a VM that gets out through a second network, and it offers to restart one started outside devvm confined, or stops it when there’s no terminal to ask in.

Spreading beyond the VM

  • Your agents’ config. A rogue agent could add a hook to ~/.claude/settings.json or a skill to ~/.claude/skills, so that it runs the next time you use the agent on this machine. devvm mounts the agents’ config folders read-only, which this machine enforces, and copies their files in on every launch, so nothing the VM changes goes back (mounts). Only devvm agent save copies a VM’s settings into devvm’s agent store, for every VM, and it shows what changed and asks first, so read its diff for hooks, MCP servers and plugins you didn’t add (saving a VM’s settings).
  • Other projects and other VMs. Each project folder gets its own VM with its own disk, and a VM mounts only its own project folder. Each VM’s proxy has its own password, so one VM can’t use another’s secrets. A VM reaches a service in another VM only through a link between VMs that you add in its folder, to a port that the other VM’s folder publishes. A link joins the two VMs’ trust, because code in one can often run code in the other through its service, so a VM links only to a VM on its own tier or a stricter one, and nothing in a VM can add a link (links between VMs).
  • Images, layers and devvm itself. Malware could try to make itself permanent by editing an image, a layer script or devvm’s own files. devvm builds images with nothing from this machine mounted, and the shared tools are read-only in every VM. devvm also refuses a project folder that holds its own folders or sits inside them, so a VM can’t reach the layer scripts that every build runs or the files devvm runs on this machine (only the project folder).
  • A folder made again. If you delete a repo and clone another at the same path, the new folder never gets the old VM’s disk or anything left in it. devvm knows a folder by its inode as well as its path, so it refuses and offers devvm rm or devvm adopt (a folder made again).
  • A devcontainer.json that reaches this machine. Other tools run a devcontainer’s initializeCommand on the host. devvm never runs it, refuses ${localEnv:…}, adds no mounts from the file and doesn’t follow a link out of the folder (devcontainer.json). devvm uses the file’s image only when the image’s registry gives it to anyone who asks, and it refuses a registry on this machine or its network. Behind a company proxy, devvm looks the image up through the company proxy and checks only the registry’s name, so a company proxy that reaches this machine or its network for a name that looks public takes the lookup there (the design note).
  • Impersonating a VM. ssh checks a VM against host keys that devvm reads through the VM’s backend instead of over the network, so a program that answers on the VM’s port in its place is refused (ssh access by name).

Kept inside the VM

The attacks in this section run the attacker’s code, and devvm doesn’t stop that code from running. It runs in the VM, as the VM’s user, who has passwordless sudo. From there it reaches the project folder, or with --clone the VM’s own clone of it, and the secrets the VM uses, which are placeholders on every tier. It reaches what the VM’s tier allows: the hosts on the allowlist on the allowlist tier, every public host on the internet tier, and the whole network on the open tier. Everything in Blocked still holds. What the code writes into the project folder can still reach you when a program on this machine runs it, which Left to you covers.

Install and build scripts

  • npm, yarn, pnpm and bun lifecycle scripts. A package’s preinstall, install, postinstall and prepare scripts run any command when the package is installed, and most npm attacks use them. pnpm’s build approvals (pnpm approve-builds) and --ignore-scripts narrow which packages run scripts, and they’re still worth using, but a package you approved runs its scripts all the same, even one compromised after you approved it. In a VM, those scripts reach only what this section’s introduction lists.
  • Python packages. Installing a source distribution runs its setup.py or its build backend, and a .pth file in site-packages runs code every time Python starts.
  • Ruby gems. A gem with a native extension runs its extconf.rb when it’s installed, and Bundler can install gems straight from a git repo.
  • Rust build scripts and procedural macros. build.rs and procedural macros run on cargo build and cargo check, and also when rust-analyzer opens the project, so opening the folder in an editor is enough to run them. With devvm code, VS Code’s extensions, rust-analyzer among them, run in the VM (devvm host and devvm code).
  • Go modules. Go has no install scripts, but cgo passes flags to the C compiler, go generate runs commands, a toolchain line in go.mod makes Go download another toolchain, and a module’s init functions run in every test and program that imports it.
  • Makefiles, task runners and curl | sh. A Makefile, a justfile or a project’s install line from its README runs whatever its author wrote.

Bad packages and images

  • Typosquatting, dependency confusion and made-up names. Attackers publish packages under names one typo away from popular ones, under a company’s internal package names with a higher version, and under names that AI coding agents invent and that attackers then register. Their code runs as the scripts above do.
  • Compromised maintainers. A trusted package can turn malicious when its maintainer’s account is taken over or a new maintainer joins with bad intent, as event-stream (2018) and xz (2024) did. Updating such a package runs its new code in the VM.
  • Malicious images. An image from --from or from a devcontainer’s image runs its own code as root in the build VM (the image is untrusted). devvm uses only images that the registry gives to anyone who asks anonymously, never one that only your Docker or your registry login reaches, and it confines builds so they reach the internet but not this machine’s services (read-only and confined builds).
  • A devcontainer.json’s commands and features. A project’s postCreateCommand and its other commands run in the VM as the VM’s user, as soon as devvm makes the VM. Its image and features decide what’s in the VM, and devvm adds its ports to the ones it forwards to this machine’s localhost, even beyond a list you narrowed, so the VM is the project’s from the start. Its features can only be devvm’s own layers, so devvm never fetches or runs a feature’s script. devvm --no-devcontainer skips the file for a project you don’t trust that far (devcontainer.json).

Rogue agents

  • Prompt injection. Instructions hidden in a README, an issue, a code comment, a web page, a dependency’s docs or an MCP tool’s output can turn a coding agent against you. devvm can’t tell an agent’s own work from injected work, so it limits what the agent reaches instead. An attack like this needs private data, untrusted input and a way to send the data out. On the allowlist tier, the only way out is the hosts on the allowlist, which Left to you covers.
  • Agents with their checks off. An agent run with claude --dangerously-skip-permissions or codex --dangerously-bypass-approvals-and-sandbox acts without asking, and a mistaken rm -rf ~ or sudo command reaches only the VM. The project folder is still the agent’s to change, so commit often, or use --clone to keep the agent’s work apart until you fetch it.
  • Malware that stays. Anything the attacker leaves in the VM, such as a cron job, a changed shell startup file or a backdoored program, stays in that VM and goes into no other, unless you save an agent’s settings that it changed with devvm agent save. devvm never deletes a VM on its own, because it may hold unsaved work, so save what you need and run devvm rm, then make the VM again.
  • Mining and resource abuse. A VM’s CPUs, memory and disk are capped by its size, which devvm size shows and changes (size). The VM’s proxy on this machine carries at most 1024 tunnels for it at once, but it doesn’t count the VM’s plain HTTP requests in absolute form or its idle kept-alive connections (the proxy).

Narrowed, not closed

Secrets and keys the VM may use

  • Worms that use your GitHub token. Shai-Hulud (2025) spread through npm install scripts. It collected npm, GitHub and cloud credentials, then used them to publish repos and new versions of packages. A VM holds no npm or cloud credentials, and its GitHub token is a placeholder. The proxy still puts the real GitHub token into every request to GitHub’s hosts, so a worm in the VM can push, make repos and do whatever else the GitHub token’s scope allows. Use a fine-grained GitHub token scoped to the repos the VM needs, or bind none (saving and binding secrets).
  • Minting credentials with a secret. A VM that can use a secret can use it to make another credential that outlasts it. The proxy refuses GitHub REST calls that add an SSH key, a deploy key, a self-hosted runner or a webhook with 403, but it can’t refuse everything, such as GitHub’s GraphQL API, an OAuth app grant or other services. If a VM may have done this, rotate the secret and check the service’s keys, access tokens and runners.
  • Keys devvm can’t tell apart. devvm takes the keys out of the VM’s copies of your agents’ settings and logins only where it can tell a key from the rest. A key in other text, such as a hook’s command, stays when it neither starts like a known key nor follows Bearer or Basic. Logins that devvm can’t bind go in as they are, such as the entries of Codex’s login that devvm doesn’t know, opencode’s API keys for providers other than Anthropic, OpenAI and OpenRouter, and opencode’s well-known logins, and devvm names each one. The agents’ folders that the VM mounts whole, such as ~/.claude/skills or ~/.config/opencode/plugin, reach the VM with every file in them, so a .env in one is in the VM, and so is a private plugin marketplace’s git config with a password or an access token in its URL. Keep secrets out of those folders (what stays in the VM’s copies).
  • Your SSH agent. While agent forwarding is on, anything in the VM can use the agent’s keys to push or log in to servers, though it can’t copy them. The VM has the agent while you’re connected. devvm ssh-agent devvm limits it to the keys you add to devvm’s own agent, and an agent that asks you to approve each use, such as 1Password’s or Secretive, narrows it further.

Git

  • Submodules with their own config. The VM writes .git/index to commit, so it can add a submodule whose config sets core.fsmonitor. Host git status reads that config before devvm’s next launch finds the submodule and locks it. devvm git-protect strict stops git status and git diff from looking inside submodules, but git submodule commands still enter them, so use --clone for a repo with submodules you don’t trust.
  • Replacing .git. The VM can rename .git and put a new one in its place, or add a commondir that points git at another config. devvm reports these on each launch but doesn’t prevent them, so check what it names before you run git in the folder (what a lock can’t stop).

Network

  • Domain fronting. The proxy checks the host name that a TLS connection asks for, its SNI, but not the Host inside the encrypted traffic, so a CDN that serves many sites on one address can route an allowed connection to a site that isn’t allowed. The proxy reads the connections to hosts with a bound secret, and it refuses a request in them that names another host.
  • Ports the VM listens on. devvm forwards the VM’s TCP ports from 1024 up to this machine’s localhost, unless you list the ports with --ports, so a VM could take a port that a program on this machine trusts while that port is free, and what the VM serves there reaches whatever connects to it. devvm’s forwarder never takes a port that a program on this machine already has, or one that devvm records for a VM, but a program that binds a port on all addresses after devvm forwarded it gets its localhost connections sent to the VM. devvm ports limits what a VM forwards, and devvm ports none forwards nothing, though a project’s devcontainer.json adds its forwardPorts to that list when devvm makes the VM or devvm update reads the file (devcontainer.json, ports, port forwarding).
  • VS Code’s relays. Over Remote-SSH, which devvm code opens, VS Code forwards the ports that programs in the VM listen on, and it answers git’s prompts with your GitHub sign-in. devvm turns both off in the VM’s VS Code settings each time it sets the VM up, but the VM can turn them back on, so turn them off in your own VS Code settings as well (VS Code).
  • What a VM does through a link. A link between VMs joins the two VMs’ trust. Code in the client can often run code in the target through the service it reaches, such as Postgres’s COPY … TO PROGRAM, and it then has the target’s network, the secrets it may use and its project folder. devvm limits a link to the ports the target publishes, on the target’s loopback, and a client to targets on its own tier or a stricter one, but it doesn’t limit what the service does. In a group, every VM trusts every other in the same way, and a VM that joins later gets the same reach (links between VMs).
  • History imported from a less strict tier. An export of agents’ history carries what the old VM’s agents read, so importing one from an open VM into a VM on the allowlist tier can bring in credentials and data that the new VM couldn’t reach itself, along with any instructions planted in them. devvm warns before such an import, and before importing an export whose tier it has no record of, but it imports all the same. Import history only from a VM you trusted as much as the new one (importing history).
  • What one VM learns of another through the shared Nix cache. VMs with the nix layer share one cache of Nix’s packages on this machine. A VM can tell by how fast the cache answers whether some VM fetched a public package. The packages are public, and a project’s flake.lock names the ones it needs, so this tells a VM only that another project on this machine uses a package. A VM that fetches many packages can also fill the cache up to its cap and push other VMs’ packages out, so they download them again, but it can’t fill the disk past the cap or keep anything that cache.nixos.org didn’t sign (the shared Nix cache).
  • Through a company proxy. The company proxy looks up the names it’s sent itself, and it may get another answer than this machine did, or a later one, so the VM’s proxy can’t check every address a name leads to there. Under a name that an allowlist names, a VM reaches whatever the company proxy reaches, such as your company’s internal hosts and the company proxy’s own host, which is this machine’s loopback when the company proxy runs on this machine, as a VPN client’s does. A name that the VM’s allowlist doesn’t allow never reaches the company proxy (the design note).
  • Which names resolve to internal addresses. When the proxy refuses a name because this machine’s lookup gives it an internal address, its refusal says so, so a VM can learn which names this machine’s DNS resolves to internal addresses. The refusal never names the address, this machine’s DNS server or the company proxy, which stay in the proxy’s own log (log files).

This machine

  • A nested project replaced through its parent folder’s VM. A project with a VM of its own inside a folder with another VM is in both VMs, so code in the parent folder’s VM can replace the nested project folder with a link, such as one to your home folder, which the nested VM would mount at its next start. devvm warns each time it makes or opens such a nested VM, naming the parent folder’s VM. It checks the nested folder, by its path and by the folder itself, just before it starts the nested VM and again once the VM runs, and it refuses the start or stops the VM again when the folder was replaced. On macOS the VM mounts the folder itself rather than its path, so it never mounts what a link points to, even when the folder is put back before devvm checks again. On Linux the VM mounts the folder by its path, so code that replaces the folder for the moment the VM’s backend mounts it and puts it back before devvm checks again stays unseen, and the VM keeps what the link pointed to until its next start. Keep a nested project that you don’t want the parent folder’s VM to reach out of the parent folder (a nested project replaced).
  • Set-id files on Linux hosts. Root in a VM can set the set-user-id bit on a file in the project folder, and on Linux hosts that bit reaches the host, so the file runs as its owner for whoever runs it. devvm names such files when it makes a VM and once a VM is stopped, but not at a launch into a running VM, and Troubleshooting says how to clear them. Don’t run programs from the project folder outside the VM (set-id files).
  • The proxy’s CA keys. Inside a VM, its CA vouches for any site, so someone with a copy of its key and a place on your network could impersonate sites to that VM. Each VM has CAs of its own, so a copy reaches one VM and no other. Only you can read the keys, they never leave this machine, and devvm keeps them out of Time Machine. Each CA lasts 30 days, so a copy goes stale, but the next CA’s key is on disk for up to 23 days before that CA starts, so a copy of it taken then works until that CA ends, up to 53 days later. Keep ~/.local/share/devvm/vms out of other backup and sync tools as well, and on Linux, which has no Time Machine, out of your backups (the VM’s CA).
  • Your company proxy’s password. No VM gets the company proxy’s settings: an open VM goes through its own proxy, which goes through the company proxy for it. devvm keeps the password out of its run logs only where it can tell it’s a password, so one in an address with neither a scheme nor a port, one with a raw /, ?, # or @ in it, or one in a run of more than 4 KiB without a space that a command writes in pieces can stay. Lima’s own log for the VM holds the password until the VM has started, when devvm replaces it with as many *, so the log still shows its length. If devvm is killed before then, or you run limactl start outside devvm, the log keeps it. With config.toml’s proxy, the mise that devvm runs on this machine gets the password in its environment, where programs that run as you can read it (open VMs and builds, the run log).

Left to you

Files the VM writes

The VM can write anything in the project folder, and devvm locks only .git. Any other file there that a program on this machine runs, or reads as its config, is the VM’s to change. --clone keeps all of these away from this machine until you fetch the VM’s work and review it.

  • Hooks in the working tree. Hooks kept in the project, such as husky’s .husky/ with core.hooksPath pointing there, run on this machine, and so do an include.path or a hook symlink that leads into the folder. devvm warns about them when it makes the VM (not covered).
  • Agent config in the project. Claude Code reads a project’s .claude/settings.json, whose hooks run commands, and .mcp.json, which starts MCP servers, and agents follow a project’s CLAUDE.md and AGENTS.md. Running an agent on this machine in the folder after the VM has worked in it runs what the VM wrote, so run your agents in the VM.
  • Editor and tool config. VS Code runs .vscode/tasks.json tasks set to runOn: folderOpen and starts the interpreters and formatters that .vscode/settings.json names. direnv loads .envrc, and mise reads mise.toml’s environment, hooks and tasks. Keep VS Code’s workspace trust on, and use direnv’s and mise’s own approval prompts.
  • Project code and binaries. npm install, make, a test run or ./bin/tool on this machine runs whatever the VM wrote. Run them in the VM instead.
  • Symlinks out of the folder. The VM can create a link in the project folder that points at a file of yours, such as ~/.ssh/id_ed25519. A program on this machine that follows it, such as an upload, an archive or an agent reading files, reads your file instead. devvm itself never follows a link out of the folder.
  • Backdoors in code you merge. Treat the VM’s commits as an untrusted contributor’s, and review them before you merge, deploy or publish them.
  • Secrets in the project folder. A .env file, a project .npmrc or a cloud key in the folder is in the VM. On the allowlist tier it can reach only the hosts on the allowlist, on the internet tier any public host, and on the open tier anywhere. Keep secrets out of the project folder, or use --clone, which copies no untracked files into the VM. The same goes for your agents’ config folders, which keys devvm can’t tell apart covers (mounts).

The network

  • Allowed hosts. Anything an allowed host accepts can carry data out. github.com accepts a push from anyone with an account, including an attacker with an account of their own, and the npm registry accepts packages the same way. Keep allowlists short, and check what a VM reached with devvm network log.
  • What your secrets allow. A VM can push with a GitHub token it may use and spend Claude quota. Use a fine-grained GitHub token, and bind only the secrets a VM needs.
  • Open VMs. An open VM, because you chose open or passed --network open, reaches everything this machine can, including its services on localhost, such as other VMs’ ports, dev servers and databases, and your local network, directly and through its proxy, which applies no rules for it. Its proxy still puts its secrets in, so it can spend them on their hosts as any VM can, but it holds only their placeholders, as every VM does. A VM started outside devvm, such as with limactl start, or one running since before devvm network gave it a confined tier, runs unconfined in the same way until devvm restarts it confined (the self-check).
  • Your browser. Programs in a VM can open URLs in this machine’s browser, and a page that a VM serves on a forwarded port runs in your browser like any other. From there it can reach the internet past the VM’s tier, and your services on localhost.
  • Remote forwards you add. A RemoteForward in your ssh config, or an ssh -R you type, makes this machine connect to whatever it names for the VM. devvm’s ssh entries can’t turn off a RemoteForward of yours without also refusing an ssh -R you type. The VM’s ssh server refuses a remote forward on any address outside 127.77.0.0/16, the range devvm keeps for links between VMs, so one on the VM’s localhost, which ssh -R asks for by default, is refused. Root in the VM can change that setting, though, and the server allows a forward on an address in 127.77.0.0/16 for anyone it lets in. A forward you ask for by a host name that begins with 127.77. binds whatever address that name resolves to in the VM. So keep remote forwards out of Host *, and don’t forward into a VM you don’t trust (ssh into VMs).
  • A company CA you add. A company CA that you put in ~/.config/devvm/ca can read the TLS traffic of every VM, whatever its tier, as it can this machine’s, and the proxy trusts it for its own connections. Only that folder adds CAs to the proxy, and nothing a VM sends can.

The platform

  • .git on Linux hosts. Linux has no flag a user can set to lock a file, so VMs on Linux hosts have no .git protection, and the VM can change hooks and config that run on the host. Use --clone there (Linux hosts).
  • Escaping the VM. A bug in Lima, Apple’s Virtualization framework or QEMU could let code out of the VM.

Found a way out of a VM? See SECURITY.md.

Last updated on