The keys were in their console
On the night of October 16, someone got into a legacy system at OpenCode and reached the OpenAI, Anthropic and Google API keys that about 1.4% of OpenCode Console users had saved in their workspaces. OpenCode called it a large-scale distillation attack, and users reported provider bills they didn't run up. In Bromure Agentic Coding, provider keys stay encrypted on your Mac, multi-provider routing runs on your Mac, and any copy of a key that leaves the VM is a stand-in no provider accepts.
Your laptop was fine. Your Anthropic key was stolen from a server you had pasted it into months ago.
On Saturday, October 17, OpenCode told some of its users that it had "identified unauthorized access to a legacy system," one it was in the middle of decommissioning. The intrusion happened overnight, from October 16 into the 17th. Its notice said that "third party provider keys (eg OpenAI, Anthropic) saved in your workspace may have been exposed." OpenCode put the share of affected OpenCode Console users at about 1.4%, limited to accounts with external providers linked, and emailed each of them. It described the incident as "related to a large scale distillation attack" and said it was working with Anthropic, OpenAI and Google. OfficeChai, Startup Fortune and others covered it the same day.
OpenCode said it could not confirm whether the keys had been used, and that the incident was ongoing. Users posting on X reported charges on keys they had only ever used with OpenCode, some in the hundreds of dollars. The advice everyone printed was the same: revoke every key you saved in the Console from each provider's dashboard, issue new ones, and update every place the old key lived.
The victims hadn't run a bad package or opened a poisoned repository. An intruder took their keys from a server they had pasted them into.
Why the keys were there
OpenCode is an open-source coding agent that talks to more than 75 model providers. The Console is its hosted side, where you can save your own provider keys in a workspace and let the service use them for you. The ai-tldr summary describes them as keys saved "for bring-your-own-key use." It's a convenience: one account, every provider, no key juggling across laptops.
It also turns a vendor's database into a key ring. Every user who linked a provider added one more live, billable credential to the same store. Months later, a system the vendor was retiring still had access to that store.
A model API key is spending authority. Whoever holds it can buy inference on your account until you revoke it, at whatever rate the provider allows. The reported motive, "distillation," means harvesting a strong model's answers at volume to train a cheaper one. That takes a lot of requests, and a stolen key makes someone else pay for them.
One copy, on your Mac
Bromure Agentic Coding runs Claude Code, Codex, Grok, Kimi and omp in Linux VMs on your Mac. You register each model provider once, in Preferences › Models: paste an API key, or click Sign in with provider to use a Claude, ChatGPT, Grok or Kimi subscription with no API key at all.
The keys go into models.enc in the app's support folder, encrypted with
AES-GCM under a per-install master key. That master key lives in the macOS
Data Protection Keychain, bound to the app's signing identity, with iCloud
sync off. It never leaves the Mac. Bromure has no account for your keys to
live in, and no hosted workspace they sync to.
Bromure gives you the console's convenience on the Mac. Every machine reads the same board, and a machine can override it with its own keys. Codex, Grok, Kimi and omp can reach Bedrock, OpenRouter, xAI and Moonshot through a translating proxy that runs on the Mac and holds the real key there. Claude Code reaches OpenRouter and z.ai directly with a stand-in.
Everything in the VM is a stand-in
The agent still needs ANTHROPIC_API_KEY or OPENAI_API_KEY to start, and
it gets one. Inside the VM those variables hold stand-ins shaped like the
real thing: sk-ant-api03-brm-… for Anthropic, sk-brm-… for OpenAI,
xai-brm-… for xAI, sk-kimi-brm-… for Kimi. The agent's HTTPS goes
through a proxy on the Mac, which swaps the stand-in for the real key only
on requests to that provider's own hosts: anthropic.com, openai.com,
x.ai, moonshot.ai. Matching is exact or subdomain, never substring, so
api.openai.com.evil.example gets nothing.
With a subscription it's the same, minus the key. The sign-in runs in a throwaway VM or through the agent's own login, the proxy captures the OAuth tokens on the Mac, and the agent keeps a stand-in. The host refreshes the access token about five minutes before it expires. The VM never holds a refresh token.
Plenty of tools now offer to sync their settings to the vendor's cloud: a
CLI that "backs up" its config, an editor that keeps your workspace in your
account, a plugin with a dashboard. Inside a Bromure machine, the config
those tools upload holds sk-ant-api03-brm-…. A stand-in stored on someone
else's server is worthless there. No provider accepts it, and it only turns
into a real key when the request passes through your Mac to the provider
it was minted for.
The proxy also catches the upload itself. It scans every outbound request, headers and body, for stand-ins headed somewhere other than their own provider. A config sync that carries an Anthropic stand-in to a third-party server gets HTTP 451. Nothing is forwarded, the VM pauses, and the Mac shows This environment may have been compromised, naming the token preview, the credential, the host it belongs to and the host it was sent to. You hear about it the day a tool tries to copy your key off the machine, months before any vendor's breach notice.
The morning after, in Bromure
Say you got that email anyway, because you also used a key somewhere else. Every guide says the same three things: revoke, replace everywhere, and check usage. Each step is short in Bromure.
Replace everywhere. The real key lives in one place. Paste the new one
into the provider's popover in Preferences › Models and Bromure updates
every running machine about a second and a half after you stop typing: the
swap map, the agents' environment and their config files. Agents whose
credential changed restart in their tab with their resume flags, so the
conversation carries on, and the VM never reboots. There are no .env
files, CI secrets or teammate laptops to chase for the copies inside the
VMs, because those copies were stand-ins.
Check usage. At AI request details, the tracing level new machines
start with, the Mac logs every exchange
with a model provider as an llm.request record: provider, host, model,
status, and input, output and cache token counts. When a provider dashboard
shows a spike at 3 a.m., you can line it up against what your machines
sent. bromure-cli trace summary and bromure-cli trace hostnames
give the per-machine view in a terminal. Every swap of a provider key appears in the
Security Timeline as a Credential brokering row, with a masked preview
and the host, in a table with a Workspace column. Anything on the
provider's bill that your machines didn't send came from someone else.
For a team, Bromure Enterprise Manager rolls the same llm.request
counts up per user, per workspace and per model, without uploading prompts,
responses or secrets. A stolen key shows up as spend that doesn't match any
install.
Or skip the key. For Claude Code, Codex, Grok and Kimi, a subscription sign-in replaces the pay-per-use key, and the tokens it produces stay on the Mac and refresh there. That leaves no long-lived API key for a third party to store.
One encrypted copy, on your Mac
Provider keys and sign-ins sit in models.enc, under a master key in the Data Protection Keychain. Bromure has no hosted workspace or account that holds them.
Multi-provider routing, locally
Every machine reads one Models board. Agents reach other providers through a proxy on the Mac that holds the real key.
Stand-ins wherever a copy lands
The VM, its config files and anything a tool syncs to the cloud hold stand-ins. A stand-in sent to the wrong host gets a 451 and pauses the machine.
Rotate once, audit per request
A new key reaches every running machine without a reboot. Each model exchange is logged with its model and token counts.
Where a key should live
Every place you paste a provider key is another place it can be stolen from. Laptops get stealers, repositories get scraped, and as this week showed, vendors retire systems that can still reach their customers' keys.
Keep the real key in one encrypted file on your Mac, and put stand-ins everywhere else. For the laptop-side version of the same problem, read The stealer packed the stand-ins and The agent leaked its own key.