diff --git a/FORK-AUDIT.md b/FORK-AUDIT.md index 269d47aa2..40224a55d 100644 --- a/FORK-AUDIT.md +++ b/FORK-AUDIT.md @@ -54,16 +54,52 @@ argument. Local-only exposure, but an exec-shaped footgun in a codebase that otherwise doesn't do this. **Status: REMOVED.** JSON-only now. -### 1.5 Copilot auth plugin: token handling + request sniffing (DELETED) -Before removal, the GitHub Copilot integration: -- used an OAuth *refresh token* directly as the API bearer token, -- stripped inbound `authorization`/`x-api-key` headers and replaced them, -- JSON-parsed every outgoing request body to guess "is this vision? is this an - agent?" in order to set policy headers (`x-initiator`, - `Copilot-Vision-Request`) that GitHub's gate required. -This was reverse-engineered policy evasion, ~5,400 lines, self-described in -its README as "temporary… avoid making edits." -**Status: DELETED entirely**, including the vendored AI-SDK fork behind it. +### 1.5 Copilot auth plugin: token laundering + request sniffing (DELETED) + +The GitHub Copilot integration routed every inference request through a custom +fetch override (retrieved here from git history, `copilot.ts` auth loader): + +```ts +const headers: Record = { + "x-initiator": isAgent ? "agent" : "user", + ...(init?.headers), + "User-Agent": `opencode/${InstallationVersion}`, + Authorization: `Bearer ${info.refresh}`, // GitHub OAuth refresh token + "Openai-Intent": "conversation-edits", +} +if (isVision) headers["Copilot-Vision-Request"] = "true" +delete headers["x-api-key"] +delete headers["authorization"] +return fetch(request, { ...init, headers }) +``` + +**Token laundering, precisely:** three operations on every request. + +1. *Re-credentialing* — the long-lived GitHub **OAuth refresh token** from + plaintext `auth.json` was presented as the Bearer session credential for + Copilot's inference endpoints. Your GitHub identity became the API key. +2. *Stripping prior credentials* — inbound `x-api-key` / lowercase + `authorization` headers were deleted so only the laundered token rode the + wire (case-sensitivity quirk spared the one they had just set). +3. *Impersonation of sanctioned-client behavior* — `x-initiator`, + `Openai-Intent`, and `Copilot-Vision-Request` are GitHub policy-gate + headers. Unofficial clients are rejected without them; values were + fabricated by JSON-parsing every request body across three API formats to + guess "vision?" and "agent?". + +**What it accomplished:** converted one OAuth device-flow consent into +standing access to Copilot's paid model APIs from an unsanctioned client, +with per-request header fabrication sufficient to pass GitHub's gate — while +avoiding any implementation of short-lived token exchange/rotation. + +**Why dangerous:** long-lived credential transmitted on every call (one +logged/proxied request captures a token with a huge blast-radius window); +plaintext storage at rest; blind stripping destroyed corporate proxy auth +headers; ToS exposure borne unknowingly by users. + +~5,400 lines total including the vendored AI-SDK fork behind it, +self-described in its README as "temporary… avoid making edits." +**Status: DELETED entirely.** ### 1.6 Hardcoded OAuth client IDs in source (LOW) Device-flow client IDs for xai, DigitalOcean, Snowflake, Codex (and formerly