On 17 October 2026, the team behind the open-source coding agent OpenCode said it had "identified unauthorized access to a legacy system". The system was one they were in the middle of decommissioning. Their warning to users: "third party provider keys (eg OpenAI, Anthropic) saved in your workspace may have been exposed" (OfficeChai).
About 1.4% of OpenCode Console users were affected, all of them people who had linked external model providers. Some users reportedly saw charges on their OpenAI and Anthropic bills before the first notice arrived (Startup Fortune). That detail matters most. For those users, the first sign of trouble was the invoice.
This is not a story about a rogue agent. It's an older pattern: a credential stored somewhere convenient, outliving the system it was meant for. It's worth looking at closely because nearly every engineering team adopting AI coding agents now has dozens of these keys in places nobody has inventoried.
What happened
Here is what has been confirmed so far, mostly from OpenCode's own statements as reported by OfficeChai and Startup Fortune:
- The compromised system was a legacy part of OpenCode Console, the hosted dashboard where users manage accounts and linked provider credentials. It was being shut down when it was breached.
- Exposed data: third-party model-provider keys that users had saved in their workspaces. OpenCode says it found no evidence so far that other data leaked.
- OpenCode described the incident as related to a "large scale distillation attack" and said it was working with Anthropic, OpenAI and Google on remediation.
- Its advice to affected users: revoke and reissue every linked key directly in each provider's dashboard (not through links in emails), update anything that used the old keys, check usage back to 17 October, and set spending limits.
- The investigation is ongoing. OpenCode hasn't said how the attacker got in or when the access was detected.
The "distillation" label has been questioned. Researcher Nathan Lambert asked whether it describes the incident accurately, and Startup Fortune points out that distillation might explain what someone does with stolen keys, but not how the keys were taken. For a security leader, the motive matters less than the fact that live, billable credentials sat in a system on its way out.
Why it happened: keys live in more places than you think
Model-provider keys spread for understandable reasons. A developer wants the same agent setup on a laptop, a desktop and a CI runner, and a hosted console that stores the key once is the easy answer. The key works everywhere, never expires, and is usually scoped to an entire organisation or project because that's the default. Four weaknesses then add up:
- Copies nobody tracks. The same key ends up in a vendor console, a local config file, a shell profile, a .env file and a CI secret. Each copy is a separate exposure, and no single team owns the list.
- Long-lived, broad scope. A key that can call every model with no spending cap is worth a lot to an attacker. Running up charges and extracting model outputs are both obvious uses.
- Decommissioning without secret hygiene. A system being retired gets less attention, fewer patches and fewer eyes, yet it may still hold live secrets. Shutting down a system should include purging or rotating every credential it held.
- Billing is the only alarm. If the first signal is a provider invoice, detection depends on someone in finance reading it carefully.
There's a second lesson in OpenCode's own SECURITY.md, which is commendably blunt: "OpenCode does not sandbox the agent", and its permission system "exists as a UX feature to help users stay aware of what actions the agent is taking" and "is not designed to provide security isolation." The project recommends a container or VM for real isolation. That isn't a flaw in the breach. It's an honest statement of where the vendor's responsibility ends. The security boundary for what an agent can read and send has to be one you own.
The permission system exists as a UX feature to help users stay aware of what actions the agent is taking; it is not designed to provide security isolation.
OpenCode SECURITY.md
The control: treat model-provider keys as production credentials
Nothing below is new. It's the same discipline most teams already apply to cloud and database credentials, applied to a type of key that arrived quickly and outside the usual process.
- Inventory. Know which AI coding agents run on which machines, which providers they call, and where each key is stored: local file, vendor console, CI, or a gateway.
- One key per tool, per purpose. Don't share a single organisation key across every agent and pipeline. Separate keys make rotation fast and contain the damage when one leaks.
- Spending caps and usage alerts. Where your provider supports per-project or per-workspace limits, set them. Alert on unusual volume or new models, not just on the monthly bill.
- Prefer a gateway over pasting keys into third-party consoles. Routing agent traffic through an organisation-controlled proxy or SSO-backed access means the real provider key lives in one place you control.
- Make secrets part of decommissioning. Before a system is retired, rotate or destroy every credential it held, and record that you did.
- Rehearse rotation. If you can't revoke and reissue every AI provider key in your organisation within an hour, find out why before an incident forces the question.
Where agent guardrails fit, and where they don't
To be clear: policy enforcement on your developers' endpoints would not have stopped an attacker getting into a vendor's server. This was a supply-chain breach, and the fix on the customer side was rotation. Runtime guardrails for agents do two other things: they limit how far keys spread in the first place, and they make scoping an incident much faster.
- Deny or Ask on credential access. Shell commands that read, print or copy files such as .env, provider config files or cloud credential stores can be set to Deny, or to Ask so a human approves the specific case.
- Outbound allow-list with Ask by default. Agents get Allow only for the provider endpoints and package registries you've approved. Anything unmatched waits for a human instead of quietly succeeding.
- Least privilege per agent. Different teams and groups get different rules, so an experimental agent doesn't inherit what production tooling is allowed to do.
- An audit trail outside the agent. When a vendor emails you on a Saturday, the first question is which machines ran that tool, when, and against which providers. An immutable log answers that in minutes, not a week of asking around.
An illustrative policy, written as pseudo-config rather than any product's exact syntax:
# illustrative only
default: ask
rules:
- match: "cat|less|cp|curl * ~/.config/*/auth*|*.env|~/.aws/credentials"
verdict: deny
- match: "network: api.openai.com|api.anthropic.com|generativelanguage.googleapis.com"
verdict: allow
- match: "network: *"
verdict: ask
audit: all_attempts # export to SIEMThis is the layer DarkControl provides for Claude Code, OpenCode, Codex, Cursor, Copilot and others. A lightweight endpoint agent checks each shell command, file write and network call against a central policy, returns Allow, Ask or Deny, and logs every attempt to an audit trail you can export to your SIEM.
The compliance angle
For organisations covered by NIS2, Article 21 lists supply-chain security and incident handling among the required risk-management measures. ISO 27001's supplier-relationship controls ask the same question in different words. An AI coding agent vendor that stores your provider keys is a supplier holding your credentials. Being able to show which agents you allow, what they may reach, how you rotated keys after a supplier incident, and when, is exactly the evidence those frameworks expect.
Want to see which agents run on your developers' machines and what they touch before the next vendor email arrives? Start with a free 7-day watch-only audit. Nothing is blocked.