All posts
Supply Chain Compromise

OpenCode Console Breach: AI Keys in a Retiring System

Attackers reached a legacy OpenCode Console being decommissioned and used stored OpenAI, Anthropic and Gemini keys to run up users' provider bills.

Securityv0 Intelligence Team OWASP: ASI06 sv0 finding: nhi_compromise
nhi-compromise api-key-theft ai-coding-tools opencode provider-keys credential-rotation

The Incident

On 2026-10-17, OpenCode disclosed that attackers had breached a legacy Console backend the company said was in the process of being decommissioned. The intrusion exposed OpenAI, Anthropic and Google provider API keys that affected users had linked into their OpenCode Console workspaces. OpenCode told the roughly 1.4% of Console users with linked external providers that their keys may have been accessed, under a notification email that read “Action Required: Potential provider key breach.” Co-founder Dax Raad said in public statements that the event hit “the OpenCode Console, not OpenCode itself” and that keys stored by the open-source opencode CLI “never come to us.” Anthropic engineer Lydia Hallie confirmed on 2026-10-17 that Anthropic had revoked Claude API keys it believed were exposed; OpenAI said it had worked with OpenCode to refund API credits that attackers drew on affected customer accounts. The intrusion vector into the legacy system has not been disclosed, and OpenCode has not published a post-mortem, status-page entry, or security advisory beyond its user notifications and X posts. OpenCode has described the event as a “large-scale distillation attack,” but outside analysts — Cyera among them — have noted that no public attribution supports the distillation framing, and no evidence that the stolen keys were used to distill models rather than simply resold or run up as bills has been published. Reported individual user losses on BleepingComputer run from roughly $400 to roughly $1,700 overnight; those figures are self-reported and not independently audited.

MITRE ATT&CK coverage: T1552.001 — Credentials in Files, T1550.001 — Application Access Token, T1078.004 — Cloud Accounts.

The Authority Path That Failed

The identity that carried execution authority at the moment of failure was the stored provider API key — a non-human identity that each affected user had minted inside their own OpenAI, Anthropic or Google account and then handed to OpenCode Console so OpenCode could call those providers in the user’s name. The scope that identity held was billable access to the user’s provider account, subject to whatever scopes and limits the user had configured. The scope it was authorized to exercise was “Console features acting for the user from OpenCode’s own hosted infrastructure.” Once exfiltrated, the same key could authorize inference and credit-drawing calls from unknown third-party infrastructure unless provider-side controls constrained it.

The trust anchor that failed first is the lifecycle around that stored key. OpenCode had already decided the legacy Console system was going away, but the decommissioning had not reached the point of forcing a credential cutover — the system that was being retired was still holding live, un-rotated multi-provider machine credentials when attackers reached it. The blast radius was multi-provider rather than single-provider because the Console design let one workspace hold OpenAI, Anthropic and Google keys together. Both gaps — “key held in a system scheduled for retirement” and “one third-party store concentrating three vendors’ production credentials” — were flaggable before the incident from an inventory view: no finding here depends on knowing the intrusion vector.

SecurityV0 Perspective

The authority analysis maps cleanly to nhi_compromise under OWASP ASI06. The attack chain did not phish a human, did not prompt-inject an agent, and did not reach an unexpected code-execution path; it consumed stored machine identities and used them to authorize billable action against three separate upstream providers. The pattern is the same shape as the LiteLLM/TeamPCP PyPI compromise from March 2026 — long-lived machine credential, held in an intermediary system, used to drive upstream work in someone else’s name — with the vector shifted from package registry to third-party credential store.

The SecurityV0 evidence pack an affected organization would have carried into this incident starts with a non-human identity inventory keyed to third-party AI tooling: for every Console, agent harness, MCP server, orchestrator or IDE sidecar linked to a provider account, which key is stored where, when it was last rotated, what provider-side spend and origin controls apply, where supported, and and whether multiple vendors are concentrated in one third-party store. Before exfiltration, the question that pack answers is “which third-party-held NHIs reach our provider accounts today, and which are long-lived, uncapped, and sitting in a system scheduled for retirement?” After exfiltration, the pack answers “which inference calls on our provider accounts came from our known agent origins versus unknown callers, which keys predate the exposure window, and which still lack provider-side spend caps right now?” Both questions are answerable from NHI metadata alone, not from the intrusion vector OpenCode has yet to disclose.

What To Do

  • Rotate every API key held by a third-party AI tooling platform today. Treat each provider key stored in any AI-coding Console, orchestrator, agent harness, or IDE sidecar as recoverable only through the provider dashboard. Revoke the key, mint a new one with the narrowest available limits, and update the third-party platform with the new value.
  • Apply available provider-side spend controls and anomaly alerts to every machine key you hand to a third party. A sharp rise in API use on a key held by a third party should create an immediate investigation and rotation path. Where a provider exposes per-key spend controls, use them; where it does not, monitor usage at the narrowest available account or project boundary.
  • Treat decommissioning as a credential-rotation event, not a status update. When any system that holds machine credentials is marked for retirement, force a cutover to new keys and purge the originals before the deprecation window opens, not after it closes. Refuse to close the decommissioning ticket until every stored credential in the retiring system is either rotated out or removed; “scheduled for retirement” is not a defensible state for a live production credential to sit in.
  • Keep an NHI inventory for every third-party AI tool that holds a provider key. For each Console, agent harness, MCP server, or orchestrator linked to one of your provider accounts, record which key is stored there, when it was last rotated, which account it bills, and whether a provider-side cap exists. If any entry reads “unknown” in those columns, you have the OpenCode-shape exposure right now.
  • Avoid concentration — do not let one third-party platform store keys for multiple providers. The OpenCode blast radius was multi-provider because single Console workspaces held OpenAI, Anthropic and Google keys together. Split provider keys across tools, or use provider-managed identity federation where it is available, so that one third-party breach cannot drain three provider accounts in a single night.

Sources