OpenCode told 1.4% of its Console users that the OpenAI, Anthropic and Google API keys they had saved in a workspace may have been exposed — and the remediation instruction it had to give them is the real finding: go revoke the key in the provider's own dashboard, because deleting it from OpenCode revokes nothing. Bring-your-own-key integrations split custody from revocation across two companies, and the asset they leak is metered compute whose only authoritative monitor is somebody else's invoice.
At a glance
What is publicly established, and what is still only reported. Reporting places OpenCode's disclosure on 17 October 2026; TechCrunch covered it on 19 October.
| Claim | Source | Status |
|---|---|---|
| 1.4% of Console users affected; every one of them emailed, and no email meant not affected | OpenCode | Company statement |
| Attackers reached a legacy system OpenCode says it was decommissioning | OpenCode | Company statement; entry vector not disclosed |
| The exposed material was third-party provider keys users had saved in Console workspaces | OpenCode | Company statement; storage design not disclosed |
| Anthropic and Google disabled keys they believed had been exposed | Reported | Widely reported, no formal provider notice |
| OpenAI worked with OpenCode to restore access and reimburse API customers for credits consumed | An OpenAI executive on X | Not a formal notice; refund mechanics unpublished |
| Unauthorised charges in the high hundreds to low thousands of dollars, inside a night | Affected users | Self-reported, unverified |
| The incident was a “distillation attack” | OpenCode's framing | No published technical evidence, no indicators of compromise |
Treat the bottom three rows as reporting rather than fact. The argument below does not need any of them. It needs only the first three and the sentence OpenCode had to put in its remediation advice.
The remediation instruction is the finding
Read the advice affected users were given, in order: replace the key at each provider, update the applications that use it, and review recent usage. Nowhere in that sequence does OpenCode's own product do anything. It cannot. A provider API key is a bearer credential issued by OpenAI, Anthropic or Google and validated by them on every request; the only party that can make it stop working is the party that signed it. OpenCode could delete every copy it holds and the leaked string would keep buying inference until somebody logged into a dashboard belonging to a different company.
This is a different shape from the breaches most incident plans are written for. When a vendor leaks your data, the vendor can contain it: pull the system, rotate its secrets, close the hole. When a vendor leaks your credential to a third party, containment is not available to anyone in the incident. The vendor knows the key leaked and cannot kill it. The provider can kill it and does not know it leaked. You are the only party holding both facts, and you learn the first one by email.
The interface makes this worse rather than better, because the affordance is there and it is a no-op. Disconnecting an integration, deleting a workspace, removing a saved key — all three read as revocation to anyone who has used an OAuth consent screen, where disconnecting really does invalidate the grant. Here the same gesture deletes a copy. The lifetime of the credential was never under the vendor's control, so no button in the vendor's UI can shorten it.
Who holds what
Every row in that matrix is missing something the other rows have, and the gaps compose into a specific operational failure. The provider can revoke but has no reason to until someone tells it. The vendor knows but can only ask. You can act but are not holding the log. There is no single party for whom this incident is actionable within their own systems, which is precisely the definition of a separation that was not designed.
The asset was spend, and its monitor is a bill
The thing that makes a stolen provider key unusual is not how it was stored. It is what it converts into. A leaked database row has to be sold, correlated or reused before it costs anybody anything. A leaked provider key is already liquid: it buys GPU time at a published rate, from the first request, billed to you.
That changes where the detection has to live. The attacker's requests never touch your infrastructure — they go from their machine to the provider's endpoint. Your gateway logs nothing. Your SIEM sees nothing. Your rate limiter is not in the path. The authoritative record of the abuse is the provider's usage dashboard, and the authoritative alarm is a billing threshold, which is the one signal in most organisations that is reviewed monthly by someone in finance rather than continuously by someone on call. The users who caught this caught it because an overnight charge was large enough to generate a provider email.
Priced properly, a long-lived provider key with no cap is an uncapped line of credit issued to whoever holds the string. That is the blast radius to write down, and the numbers reported here — hundreds to a few thousand dollars in a night, per key — are the floor rather than the ceiling, because they describe an attacker spending casually. An attacker spending deliberately against a key with no limit is bounded only by the provider's own rate limits and fraud heuristics, neither of which you configured.
Two spend controls are worth more here than any amount of rotation hygiene, because they bound the loss before you know about it: a hard per-key monthly cap set at your actual expected usage rather than at a comfortable headroom, and a separate key per integration so a cap is attributable. A key with a $50 cap that leaks is an incident report. The same key uncapped is a negotiation with your provider's billing team.
“Distillation attack” is a motive, not an indicator
OpenCode framed the incident as a distillation attack — stealing keys to generate training data from frontier models. It may be right. But as of this writing it has published no technical evidence linking the exposed credentials to distillation activity, and no indicators of compromise at all: not the entry vector, not how the keys were stored, not what the attacker's traffic looked like.
A motive is not actionable and an indicator is. If the campaign had been described by request shape — model, sampling parameters, prompt distribution, concurrency — every other vendor holding customer keys could have gone looking for it this week, and so could the providers. Naming the motive instead does one thing the indicators do not: it moves the story from “a company stored bearer credentials in a legacy system” to “a company was targeted by sophisticated adversaries.” Both can be true. Only one of them generates a detection.
This is the pattern to watch for in agent-tool incident reports generally. The useful question is not who and why; it is what a peer can grep for tomorrow. On that measure this disclosure is, so far, a notification rather than a report — which matters because the vendor is the only party who can produce one.
What to build instead
The design rule falls straight out of the matrix: never hand a long-lived provider key to a third party's web workspace, because doing so transfers custody without transferring the ability to revoke. Three alternatives exist today, in increasing order of how much work they are and how much they buy.
| Approach | Who can revoke | What it costs you |
|---|---|---|
| Dedicated key per integration, hard spend cap, calendar rotation | Still only the provider, but the loss is bounded and attributable | Key sprawl; a rotation you will actually have to run |
| Delegated authorisation (OAuth-style) where the provider offers it | You, per client, from the provider's own console | Only available where the provider supports it for that tool |
| Your own AI gateway holding the real key, issuing the vendor a key you mint | You, instantly, without touching the provider | A service to run, and it is now in the latency path |
The gateway is the only one of the three that actually repairs the split, and the reason is structural rather than clever: it makes you the issuer. A credential you minted is a credential you can invalidate, which collapses custody, revocation and observation back onto one desk — yours. It also puts the spend meter somewhere you already page on, which is the half of this incident that no amount of rotation addresses.
If running a gateway is not proportionate for your team, the honest fallback is the first row, taken seriously: one key per tool, a cap that would be uncomfortable rather than roomy, and the knowledge that every such key is a copy you cannot recall. That is not a strong position. It is the position bring-your-own-key puts you in, and the value of this incident is that it was stated out loud in a remediation email.
FAQ
Does deleting an API key from a vendor's dashboard revoke it?
No. It deletes the vendor's stored copy. The credential remains valid until it is revoked in the issuing provider's own console — OpenAI's, Anthropic's or Google's. This is the specific instruction affected OpenCode users were given, and it generalises to every bring-your-own-key integration.
How would I know whether a leaked key had been used?
From the provider's usage dashboard, not from your own logs. The attacker's requests go directly to the provider's endpoint and never traverse your infrastructure, so nothing you operate is in the path. Check usage by key, by day, against your expected pattern; an unfamiliar model, an unfamiliar hour or an unfamiliar concurrency level is the signal.
Is a spend cap a substitute for rotating the key?
No, but it is the control that works while you are asleep. Rotation ends an exposure you already know about; a cap bounds one you do not. Set both, and size the cap against your real usage rather than leaving headroom you would not notice being consumed.
Was this a supply-chain attack on the agent itself?
Not as described. OpenCode says attackers reached a legacy system and read keys users had saved in Console workspaces, which is a credential-at-rest exposure in a web product rather than a compromise of the agent, its model or its distributed packages. The relevant class is how credentials get to an agent at all, not supply-chain integrity.
Should developers stop saving keys in agent tools entirely?
Where a delegated-authorisation option exists, use it instead. Where it does not, the defensible version is a key minted for that one tool, capped, and recorded in an inventory you review — because the thing you are agreeing to is that a string you cannot recall now exists on somebody else's disk.
Further reading
On this wiki:
- Credential Lifetime — why the clock on a secret matters more than its strength.
- AI Gateways — the component that makes you the issuer instead of the holder.
- Credential Delivery to the Sandbox — getting a secret to an agent without leaving it somewhere.
- When the Credential Broker Is Compromised — the failure mode this incident is an instance of.
- Denial of Wallet & Cost Attacks — spend as an attack surface.
- Access Reviews for Agent Credentials — the inventory that tells you which keys are out there.