Blog
min read
The Week of Sandbox Escapes: A time bomb in .vscode: bypassing Antigravity's Secure Mode
%20(1).png)
This post is part of The Week of Sandbox Escapes, a series on how AI coding agents keep crossing the line between sandboxed workspace actions and unsandboxed host execution. Read the master report here.
Antigravity ships with a sandbox and a Secure Mode. The agent can write code and run code, but it's boxed in, so a bad prompt can't wreck your machine. The write tools back this up. write_to_file and edit_file refuse to write anywhere outside your working directory, and inside it they block the obvious landmines: .git, and a set of sensitive names under .vscode as well. It reaches into the config folder and guards the entries someone decided were dangerous.
tasks.json wasn't one of them.
Why a config folder is dangerous
VSCode tasks can be set to run the moment a folder opens. You put "runOn": "folderOpen" in tasks.json, flip task.allowAutomaticTasks to "on" in settings.json, and the next time that workspace opens, your task runs with no prompt. This is a documented VSCode feature, not a trick. Antigravity is built on VSCode, so it inherits the behavior.
Now line the two facts up. The agent is sandboxed. Writing tasks.json is allowed, because it's the one name in .vscode that never made the blocklist. So under prompt injection, the agent drops it in, along with two supporting files:
That's all three. tasks.json carries the command, settings.json flips automatic execution on so nothing prompts, and launch.json gives the task a second way to fire. None of it trips the sandbox, because dropping config files is exactly what the sandbox is fine with.
Then the payload just sits there. It does nothing until the user restarts Antigravity and reopens the project. When they do, the task fires through VSCode's own task runner, not the agent's sandboxed shell. It runs on the host, with the user's privileges, outside Secure Mode.
The realistic version is indirect. A poisoned README, a comment buried in a dependency, a doc the agent reads while doing something else entirely. The instruction to write three files into .vscode doesn't read as an attack when it's sitting in the middle of a file the agent was already told to process. And that last line is the whole social-engineering budget: the injected prompt closes by asking the user to restart Antigravity, which is about the least suspicious request an editor can make.
The proof of concept writes open -a Calculator into ~/.zshrc which would open the calculator every time that the developer opens antigravity. Swap that line for anything you like: SSH keys, tokens, a persistent backdoor in your shell profile, your pick.
Takeaway
The boring fix is a one-liner: put tasks.json on the blocklist next to .git.
Except that one-liner is exactly the move that got them here. Antigravity already had a blocklist. It already reached .vscode. tasks.json walked through anyway, because a blocklist only stops what someone remembered to write down, and there is always one more auto-executing config file than you remembered. Patch tasks.json today and you're one release away from the next entry that runs itself. This is the same mistake as an (allow default) seatbelt profile, moved one layer up into the write tools: you're subtracting dangers from a default of "yes," and you will always be a step behind whoever's looking for the entry you skipped.
An allowlist flips the default. Deny every write, permit the handful of paths the agent actually needs, and tasks.json never even comes up, because it was never on the yes list. That's strictly better than a blocklist, and it's still not the fix. It's more painful to maintain, it breaks real work the first week, and it's aimed at the wrong thing anyway. All it controls is what the agent writes.
Because here's the actual shape of it. The sandbox did its job on the agent. The escape didn't come from breaking out of it. It came from writing a file that the host would later execute on the agent's behalf, after the sandbox was no longer in the loop. As long as a sandboxed writer can hand configuration to an unsandboxed component that trusts it, no list closes the gap, block or allow. The fix that outlives the next trick is the editor not trusting agent-written workspace config enough to auto-run it in the first place.
Subscribe and get the latest security updates
Back to blog
.png)
.png)
%20(1).webp)
%20(1).png)

.png)
%20(1).png)
