DEV Community

Cover image for What Cloakroom would and wouldn't have done in October's incidents
Shanjeev Rajendran
Shanjeev Rajendran

Posted on

What Cloakroom would and wouldn't have done in October's incidents

An API key is a password that also pays the bill: hold a copy and you can run up charges on someone else’s account until they revoke it. In October, developers’ keys leaked four different ways in one month.

LiteLLM 1.107.0, a popular AI gateway, shipped an update that copied its users’ keys every time Python started; the attacker got in through a master key that had been committed to a public repo. Tensorlake’s npm package 0.5.144 carried code that copied developers’ keys, used them to spread into their other packages, and planted agent config in repos. Railway, a cloud hosting company, was breached and some stored settings were decrypted. OpenCode’s hosted Console exposed the provider keys users had saved in it. I checked which steps Cloakroom touches.

Step by step

stops means Cloakroom, as shipped, prevents the step. reduces means it removes one copy or one path but not the step. none means it is outside what a local agent hook can see.

Incident, step Cloakroom
LiteLLM: master key in an agent config file, committed to a public repo, never revoked reduces (only if the commit went through an agent or Cloakroom's git hook; unknown)
LiteLLM: key used on their agent API, which returned a GitHub token none
LiteLLM: stolen token sends repo secrets to a webhook through CI none
LiteLLM: release workflow pointed at a lookalike fork none
LiteLLM: wheels run remote code at every Python start none
LiteLLM: stealer reads disk, browsers, cloud metadata none
LiteLLM: encrypted archive sent out none
LiteLLM: Claude Code puts a GitHub token in a response body reduces if it passed through a tool result; none if Claude Code added it to its own API request
Tensorlake: admin account commits the payload none
Tensorlake: npm install runs the payload reduces (narrow: only if the agent runs the install; it masks output, doesn't block)
Tensorlake: reads credential files and .env* files none
Tensorlake: plants .claude/settings.json in repos none
Tensorlake: republishes the victim's packages none
Railway: privilege escalation in build infrastructure none
Railway: encrypted variables pulled, some decrypted none
Railway: search for AI provider key names none
OpenCode: legacy system behind Console reached none
OpenCode: stored provider keys exposed none

The test

I built a git repo with 11 random dummy secrets in the places the stealers look: a .env, a gateway config file, an MCP config, npm, AWS and SSH files, and a script that prints a gho_ token the way gh auth status --show-token does. Claude Code ran the same task twice, plain and with Cloakroom 0.8.0: read the configs, run the script, write a setup file, commit. Then I scanned the model's input, the local session file and git history for the exact dummy values.

Where Without Cloakroom With Cloakroom
What the model was given 11 of 11 0 of 11
Session transcript 11 of 11 0 of 11
Git history 1 of 11 (the gateway key) 0 of 11

The agent's final answer held none in either run. Cloakroom withheld the script's whole output, so the token never reached the model.

Cloakroom refused the agent's write of the gateway key into the setup file. The agent used a placeholder and committed that file alone; the commit check rightly passed it, so it never had a key to stop. Read it as "the key didn't get committed", not as a test of the commit check.

To rerun it (two short runs on your own login): bench/black-october/run.sh

Honest limits

  • Cloakroom would not have stopped any of the four incidents. Every theft step reads disk, a server or CI directly.
  • The only steps it touches are upstream copies: a key committed through the agent, and a token passing through tool output into model context and gateway logs. Even the commit step depends on how it was made, which LiteLLM didn't say.
  • Neither stealer read agent session transcripts, so keeping secrets out of transcripts would not have changed these thefts either. Both took agent credentials straight from disk, which Cloakroom's placeholders never touch.
  • Placeholders are restored to real values in files the agent writes, by design, and Claude Code's session log records what was written (a known limit in the repo's limits file). In this run the agent wrote no values into the setup file, so that path wasn't exercised. A task that copies a key into a new file would put it back on disk and in the transcript.
  • The Tensorlake payload is mostly encoded, so what I know about what it reads comes from the plain strings only.
  • I found no first-hand statement from OpenCode, only users' issues. Railway's report is preliminary.
  • One machine, one model, one prompt: counts can move a little between runs.

In 0.8.0

Two features shipped today (2026-10-27) in Cloakroom 0.8.0 on PyPI. cloakroom exposure reports which secrets your agents saw. cloakroom scan checks a repo's agent and editor config (.claude/settings.json hooks, .mcp.json, .vscode/tasks.json) for commands that were added or changed, and a git hook runs it after checkout and merge and warns. Both report; neither blocks.

The commands are in the README's command reference.

Top comments (0)