On Saturday 17 October OpenCode, the open source coding agent with 215,000 GitHub stars, emailed 1.4% of the users of its hosted Console to say that the Anthropic, OpenAI and Google keys they had saved in a workspace "may have been exposed." The email blamed "unauthorized access to a legacy system that we were in the process of decommissioning." The public statement at 18:08 UTC called it "a large scale distillation attack," said the incident was ongoing, and said the company was working with all three providers to remediate. By Sunday there was no postmortem, no count of affected accounts, no entry vector, and no word on how the keys had been stored.

The exposure comes from a feature, not from the CLI. Console lets a workspace owner connect "provider accounts they already pay for" so that, in the words of its docs, "Console stores the credential and serves each provider through its gateway" and "members use the models without ever seeing the provider key." The same owner can set a monthly budget that makes the workspace return a 429 once it is spent. That budget is enforced by the gateway, on requests that travel through opencode.ai. A key lifted from the store and pointed straight at api.anthropic.com never travels through it. The budgets page states the general case: "With no budget set, spend is unlimited."

The only limit that follows a raw key is the one its provider enforces, and the three providers do that differently. Anthropic caps spend per workspace but not on the Default Workspace. OpenAI's hard spend limit is per organization or per project, and "enforcement is not instantaneous." Google ties a Gemini key to a Cloud project and offers billing alerts. On my own Mac the CLI's credential file sits at ~/.local/share/opencode/auth.json with mode 0600, 333 bytes, untouched since 24 September, and nothing published says that path was involved. The keys that leaked were the ones people handed to a server so their teammates would not have to hold them.

What was said, and when

The first public sign came from outside the company. At 15:18 UTC on Saturday the security researcher Matt Johansen posted that OpenCode customers were getting breach notices and that he had "some DMs that people's API keys are running up charges." Twelve minutes later he posted a screenshot of the email, subject line "Action Required: Potential provider key breach," which asked recipients to revoke and replace the keys "through the relevant provider's dashboard," update any applications using them, and "review recent usage for unexpected activity." OpenCode's own account confirmed it at 18:08 UTC: "We had a security breach last night related to a large scale distillation attack that impacted 1.4% of OpenCode Console users." Affected users had been emailed that morning. "If you did not get an email you were not impacted." Only users with external providers linked were affected. "The incident is ongoing so we cannot share more details at this point." At 18:41 UTC the co-founder Dax Raad added that "my personal accounts are being attacked now too."

The statement had 1.68 million views by Sunday morning, and the Hacker News thread, submitted seven minutes before it, reached 841 points and 157 comments without a reply from anyone at the company. The thread's most useful observations were structural: if you use the hosted Console and bring your own keys, OpenCode holds those keys on its backend, and OpenCode has no way to revoke a customer's Anthropic or OpenAI key itself, only to hand the providers the list. One user said their notice arrived alongside a message from Anthropic that their $20 monthly API credit, the allowance Max and Team plans started receiving on 7 October, had been used up. Another's OpenCode Go key was revoked with the plan's allowance untouched.

What Console does with a key

Console is the optional hosted layer around a free CLI: metered models at list price through a gateway at opencode.ai/inference, and Go subscriptions at $10 and $40 a month. Its Providers page is where the breach lives. An owner clicks Connect Provider, picks from a catalog that includes Anthropic, OpenAI, Google, xAI, DeepSeek, Mistral, Groq and OpenRouter, and pastes the key. Members run /connect, choose the workspace, and see the models. Cloud providers want more: Bedrock takes a region and an API key, Vertex AI a service account JSON file, Cloudflare AI Gateway an account ID, a gateway ID and a token, Databricks a workspace URL and a token. Every one is a credential a third party now stores for you.

The docs describe rotation as clicking the credential and entering the new key, which changes what the gateway sends and nothing else: the old key stays valid at the provider until you disable it there. Billing is explicit that "the provider bills you directly for tokens," with Console recording each request at list price so usage reports and budgets include it. What the docs do not say is how the credential is stored. There is no sentence about encryption at rest, who inside the company can read the store, or where it lives. The trust center for Anomaly Innovations, Inc., the company behind OpenCode, lists SOC 2 Type 1 and Type 2 as compliant, lists a "Credential Management" control without describing it, and has no incident history page. The email's "legacy system" remains the only description of where the keys came from.

Why the budget does not travel

The budgets page is precise about what it controls. A workspace budget "blocks requests for everyone once the workspace reaches it," members get a default or custom monthly limit, usage through a connected provider counts "at the configured price," and a request over the line fails with HTTP 429 and the text "Upstream request failed: Account budget exceeded." Every clause describes a check the gateway performs when a request reaches it. An attacker holding the raw key does not make requests through the gateway. They make them to the provider, where the key is the whole credential and the Console workspace does not exist. So the question for anyone who got the email is not what budget they set in Console. It is what limit their provider puts on that key, and there are three different answers.

Anthropic scopes an API key to a workspace at creation, and a workspace can carry a monthly spend limit and per-model rate limits set below the organization's. Two exceptions matter. "You cannot set limits on the Default Workspace," so a key scoped there answers only to the organization-wide limit. And per-user monthly caps exist in exactly one place, the Claude Code workspace Anthropic creates for Console sign-ins, which you cannot create keys in by hand. Keys can be created with an expiration of 3 hours, 1 day, 7 days, 30 days, custom, or never. Revocation is Disable on the API keys page, which sets status to inactive and is reversible, Delete, which archives it, the same update through the Admin API, or archiving the workspace, which "archives every API key created for that workspace within seconds."

OpenAI's spend limits guide describes a hard limit per organization or per project. When tracked spend reaches it, requests fail with a 429 carrying organization_spend_limit_exceeded or project_spend_limit_exceeded, and "Enforcement is not instantaneous, so recorded spend can slightly exceed the configured amount." Alerts are separate: "Spend alerts do not enforce a cap." There is nothing per key. Google's Gemini API key page says "Every Gemini API key is associated with a Google Cloud project" for billing and quota, recommends "Restrict to Gemini API only," and for cost protection recommends billing alerts. It offers no spend cap on the key or the project, and its leak procedure is to generate a new key, deploy it, then disable the old one, in that order.

The word distillation

OpenCode chose the label and, as of Sunday, has shown nothing behind it. One commenter put it in six words, "there's no public evidence of this," and others asked for the attacker's queries before accepting the account. What the label points at is well documented elsewhere. Anthropic's 23 February report counted over 16 million exchanges from roughly 24,000 fraudulent accounts run by DeepSeek, Moonshot and MiniMax, described "commercial proxy services which resell access to Claude and other frontier AI models at scale," and found one proxy network managing more than 20,000 accounts at once. A June letter reported by Bloomberg added about 25,000 accounts and 28.8 million exchanges linked to Alibaba's Qwen lab. The September threat report, which I covered then, named seven labs, put the largest campaign at 151 million exchanges, and listed per-key quotas among the mitigations it recommended to providers.

Vectoral's survey of the Chinese relay market, updated on 1 October, tracked 49 relays reselling access to Claude, Codex and Gemini at median discounts between 8.1% and 97.8%, with supply sourced from free-trial abuse, chargebacks, stolen cards and open endpoints. The oldest case it cites is from 2023: a stolen OpenAI account with a $150,000 usage limit, shared on a Discord server with more than 500 members. A key that bills someone else and carries no cap is the unit that market trades in, whatever the buyer does with the tokens. Johansen's DMs about keys "running up charges" fit that reading. A single user's exhausted $20 credit fits it too, and is also the smallest possible number.

Not the first time at Anomaly

The CLI has had two serious disclosures this year, both about its local server rather than the hosted service. CVE-2026-22812, fixed in 1.0.216, was an unauthenticated local HTTP server with permissive CORS that let any local process or website run shell commands as the user, CVSS 8.8. GHSA-632h-h47v-g4x4, found by Datadog in August and fixed on 24 August in 1.18.22, let a web page submit a cross-origin form to the /global/upgrade endpoint and have the CLI install an arbitrary npm package with an install script. Neither touched Console, and neither was a credential store.

The hosted side has its own thread. Issue 10416, opened on 24 January under the title "OpenCode is not private by default?", found the CLI reaching the company's servers to generate session titles even when the user ran local models. On 17 February the co-founder answered that the privacy policy "ONLY applies to our SaaS offering, OpenCode Zen," and that lawyers were drafting fixes. It was closed as not planned in June and resurfaced in Saturday's thread. The current release, v1.19.3, shipped the day before the breach.

What to do with the key you gave away

If you connected a provider to a Console workspace, revoke at the provider, not in Console. Rotating in Console only changes what the gateway sends. On Anthropic that is Disable or Delete on the API keys page, or POST /v1/organizations/api_keys/{id} with "status": "inactive" through the Admin API; archiving a dedicated workspace does it for every key in one action. On OpenAI, delete the project key. On Google, create and deploy the replacement, then disable the old key. Then read usage back to Thursday 16 October on all three.

When you issue the replacement, give it a container with a ceiling. On Anthropic that is a new workspace, not Default, with a spend limit set, and a key scoped to it with an expiration. On OpenAI it is a project with a hard limit, accepting that enforcement lags. On Google it is a separate Cloud project with billing alerts, because that is all there is. Do this for every gateway, aggregator or team tool that holds a provider key for you, not only this one.

Then ask whether a static key should go to a third party at all. Anthropic's identity-backed keys die with the account that owns them, and Workload Identity Federation removes the static string entirely. OpenCode's own CLI accepts {env:ANTHROPIC_API_KEY} in its provider config, so the key never leaves the machine that uses it. Console promised that members would never see the key. That promise held. The people who saw it were not members.