-
Notifications
You must be signed in to change notification settings - Fork 307
Description
Hi, I hope you can add windsurf as a Provider. I have tested it for you and it works. However, your code is confusing and I can't incorporate it. Here are my experiences that might be helpful to you. Thank you for your hard work.
Details
1. Token Storage Architecture
Windsurf stores authentication sessions using the standard Chromium encrypted storage pattern:
| Component | Location | Purpose |
|---|---|---|
| Master key | %APPDATA%/Windsurf/Local State → os_crypt.encrypted_key |
Base64-encoded DPAPI blob containing AES-256 key |
| Encrypted sessions | %APPDATA%/Windsurf/User/globalStorage/state.vscdb |
SQLite DB with secret:// prefixed entries, AES-256-GCM encrypted |
2. Extraction Chain
Step 1: Read Local State, decode the base64 encrypted_key, strip the 5-byte DPAPI prefix.
Step 2: Call CryptUnprotectData (Windows DPAPI) — succeeds for any process running as the same user, no admin required, no prompt shown.
Step 3: Use the resulting 32-byte AES-256 key to decrypt sessions from state.vscdb. The encrypted values use Chromium's v10 format: 3-byte prefix + 12-byte nonce + ciphertext + 16-byte GCM auth tag.
Result: Plaintext accessToken in the format sk-ws-01-... (103 characters), along with account metadata.
3. Verified API Access with Extracted Token
The extracted token grants full access to Codeium's backend services:
Direct API calls to server.codeium.com (Connect RPC + Protobuf):
| RPC Method | Service | Result |
|---|---|---|
MigrateApiKey |
SeatManagementService | Server returns full token confirmation |
GetPrimaryApiKeyForDevsOnly |
SeatManagementService | Returns internal UUID |
GetUserNotifications |
SeatManagementService | Server accepts token |
BatchRecordAnalyticsEvents |
ProductAnalyticsService | Successfully sends events as the user |
GetProfileData |
SeatManagementService | Server accepts token |
Via Language Server proxy (localhost Connect RPC):
| RPC Method | Result |
|---|---|
GetUserStatus |
Returns ~31KB of user data (name, email, UUID, subscription info, available models) |
InitializeCascadePanelState |
Session initialization succeeds |
StartCascade + SendUserCascadeMessage |
Full AI inference — streaming responses from Claude, GPT, Gemini models |
4. Full AI Inference Exploitation
The most critical finding: an attacker can start the bundled language server binary with the stolen token and make unlimited AI inference requests through the Cascade API. The flow:
Attacker process
→ Extract token from disk (DPAPI + AES-GCM)
→ Spawn language_server binary with --stdin_initial_metadata
→ Write Metadata protobuf (containing stolen api_key) to stdin
→ Call InitializeCascadePanelState → GetUserStatus → UpdatePanelStateWithUserStatus
→ StartCascade → StreamCascadeReactiveUpdates + SendUserCascadeMessage
→ Receive full AI model responses (streaming)
This was verified to work with multiple models including Claude Opus 4.6, Claude Sonnet 4.6, and others available on the user's subscription.