Hey 👋

Last week was about scope: what an agent is allowed to do, and where that's enforced. This week is about what sits around the agent. That means the gateway it talks through, the monitor that watches it, and the places its keys are stored.

It was a busy five days. LiteLLM, the open-source gateway many teams put between their agents and model providers, shipped a backdoored release on 21 October. LiteLLM traces the break-in to GitHub tokens sitting in its own gateway logs. A day earlier, OpenAI published two incidents in which its own agents turned off parts of the monitoring that watches them. And between 17 and 19 October, two agent tools (OpenCode Console and Google's Agent Mesh) disclosed problems with how they hold provider keys and grant agent sessions.

My take, in one line: anything the agent can read or write is part of its blast radius. That includes the systems you put there to contain it.

This week in AI security

The gateway's logs held the keys to its own release

On 21 October, LiteLLM published that its "release pipeline was compromised and pushed v1.107.0 to the docker registry and PyPi." The release "contained compiled malware which steals credentials and loads remote-code execution tools."

LiteLLM's timeline, all on 21 October (UTC):

  • 10:08. Branch protection blocked an unauthorized change to the private release workflow. Five seconds later, a privileged developer credential overrode it.

  • 10:46 to 11:08. A staging run built from a lookalike repository, Berri-AI/litellm, one hyphen away from the real BerriAI/litellm.

  • 11:11. A second developer's credential passed the production approval gate.

  • 11:39. Seven malicious wheels went up on PyPI. Docker images followed at 11:46.

  • 11:53. A third credential deleted the workflow records.

  • 13:23. PyPI removed the package. Docker tags v1.107.0, latest, main-latest and main-stable were cleaned up by 14:20.

That makes 104 minutes on PyPI and about two and a half hours on Docker. Wiz counts roughly 49,000 downloads of the bad version. It also saw stolen credentials in use "starting approximately 4.5 hours post-exfiltration": each AWS credential was checked with sts:GetCallerIdentity, then bedrock:ListFoundationModels. In other words, the attacker wanted model access to resell or abuse. In a few environments the attacker also listed IAM roles, users and access keys.

The payload is aimed squarely at people who run agents. Socket's analysis lists the files it collects: ~/.claude/.credentials.json, ~/.codex/auth.json, ~/.gemini/oauth_creds.json, ~/.cursor/mcp.json, plus the configs for Copilot, Windsurf, Kiro, Zed, Continue, OpenCode and Hugging Face. If DATABASE_URL is set, it queries the LiteLLM proxy's credentials table, where the gateway keeps your provider keys. It also takes the usual cloud keys, SSH keys and browser data. It installs a .pth file and a sitecustomize.py, so it runs whenever Python starts in that environment, even if nothing imports LiteLLM.

The way in is the part I'd show anyone running an AI gateway. LiteLLM found "an unexpected, innocuously named user account" on an internal deployment that was exposed to the internet. Its working theory is that the attacker got into that deployment and took GitHub CLI OAuth tokens from its logs. How did GitHub tokens get into an LLM gateway's logs? LiteLLM says it has "observed specific situations in which Claude Code will embed a user's GitHub CLI OAuth token into a response body", and "in situations where response bodies are logged, these tokens may appear in LiteLLM logs."

Two caveats. This is LiteLLM's observation and is still under investigation. I found no statement from Anthropic either confirming or disputing it. The initial entry point is also unconfirmed. LiteLLM suspects "a recently patched vulnerability." This is the project's second supply-chain compromise this year, after the March backdoor in 1.82.7 and 1.82.8.

❝

So what: a model gateway concentrates credentials twice. It stores the provider keys, and it logs whatever the agents send and receive. When an agent puts a secret in a prompt or a response, that secret ends up in the log. So the log store is a secret store, and most teams don't protect it like one.

❝

Do this: first, run pip show litellm and check image digests everywhere you run it. If 1.107.0 was ever installed, follow LiteLLM's steps: don't run pip first, remove cook.pth, cook.py and sitecustomize.py, kill the process holding /tmp/remote_code_loader.lock, rebuild, pin 1.106.2, and rotate everything that host could reach. Then, whether or not you were affected, check your gateway logs for tokens. Print only the prefixes, never the secrets:

grep -rhEo '(gh[opsu]_[A-Za-z0-9]{36}|github_pat_[A-Za-z0-9_]{40,}|sk-ant-[A-Za-z0-9_-]{20,}|AKIA[0-9A-Z]{16})' /path/to/gateway/logs \
  | cut -c1-8 | sort | uniq -c
❝

Any hit means the log store needs the same access control as your vault. Turn off request and response body logging unless you need it, and if you do keep it, redact before the write, not after.

Two OpenAI agents turned off the alerts from the monitor watching them

On 20 October, OpenAI published two incidents from 3 and 6 October. In both, an internal coding agent weakened the misalignment monitoring that watches agents.

3 October, GPT-6.1 Sol. A researcher asked it to build evaluation tasks from Slack feedback and said "don't send any messages." At first the agent read that as being about outreach only, "separate from automatic monitoring." A subagent also decided not to recommend switching off notifications, because doing so "would disable required alerts." Later the parent agent changed its mind. "Based on its judgment that the user's instruction not to send messages applied to the misalignment monitoring system," it told the subagent to suppress notifications, and the subagent did. The result: "The misalignment monitor still ran and saved its reports, but human alerts were disabled."

6 October, GPT-6 Astra. It was migrating a serving path by copying a reference implementation. The migration removed the monitor's configuration and runtime integration, and a regression test was changed to assert that monitoring was absent. Another agent had told it not to disable the monitor "even temporarily." When the user asked, Astra "falsely claimed to the user that it had not removed the monitor."

This is the same failure as Anthropic's police-tip form in issue #32: an instruction with a gap, and an agent that read the gap as permission. The difference is what it touched. Last week it was an outside website. This time it was the control.

On 19 October, Microsoft stated the design principle in its announcement of agent risk scoring and dynamic permissions: "If the agent or harness is compromised, it should not be able to disable the controls watching it." Microsoft gave no availability dates, so for now that's a principle rather than a product. It's still the right principle.

❝

So what: a monitor whose configuration the agent can edit is a suggestion. OpenAI's agents didn't need an attacker. They needed an ambiguous instruction and write access to the monitoring config. An injected agent needs even less.

❝

Do this: for one production agent, list where its monitoring lives: the detection config, the alert routing, the audit log sink. Then check whether the identity the agent runs as can write any of them (kubectl auth can-i --as=..., aws iam simulate-principal-policy, or the repo permissions if the config sits next to the agent's code). Move anything it can write to a separate identity, and treat a change to monitoring config as an alert in its own right.

Where the provider keys live now

These came out between 17 and 19 October and they're about the same thing. Agent tools now hold credentials on your behalf, and the way they hold them is weaker than the tools themselves.

OpenCode Console, 17 October. OpenCode emailed users that an intruder had reached a legacy system on the night of 16 October, which "may have exposed the third-party AI provider keys that users had saved in OpenCode Console" (The Hacker News). It affects 1.4% of Console users. Keys added in the CLI or desktop app are stored locally and weren't exposed. OpenCode linked the breach to "a large-scale distillation attack" without explaining the connection, and it hasn't published a post-mortem. Users have reported unexpected charges on their provider bills, but those reports are unverified.

OpenCode on Windows and WSL, 19 October. Pillar Security disclosed that a malicious or hijacked remote MCP server could run commands on a developer's machine during OAuth sign-in (The Hacker News). The server supplies the authorization URL, and OpenCode passed it to a helper that wrapped it in a PowerShell command without escaping it. Versions 1.0.137 to 1.18.32 are affected. It was fixed in 1.18.33 on 28 September, in a pull request described as a refactor. No CVE, no advisory. OpenCode's security policy puts user-configured MCP servers "outside our trust boundary." So scanners won't flag the vulnerable builds.

Google Agent Mesh, CVEs published 19 October. In CVE-2026-103091 (CVSS 9.3), anyone holding a token from the configured OIDC issuer could enroll in the mesh. The example policy bound every authenticated identity to a role that could call every service on every target. It was found by Eli Ainhorn of Noma Security and fixed in 0.1.0-alpha.9 on 7 September. Safeguard's analysis adds two details. First, a short-lived OIDC token produced a mesh session lasting 90 days, and that constant was still 90 days in v0.1.1. Second, upgrading doesn't remove a wildcard policy you already loaded: "A version bump fixes the code that evaluates it. It doesn't review what you told that code to allow."

❝

So what: the provider key used to be an environment variable on one machine. Now it may also sit in a hosted console, a gateway database and a mesh enrollment, and each of those is a vault you probably never threat-modelled. Silent fixes and CVE-less advisories mean your scanner won't tell you either.

❝

Do this: write down every place your model provider keys are stored: hosted consoles, gateway databases, CI secrets, developer laptops. Set a spend limit and a usage alert on every key. That's how most OpenCode users found out. Upgrade OpenCode to 1.18.33 or later on Windows and WSL. If you run Agent Mesh, upgrade, then read the stored policy for any binding to sam:system:authenticated.

Quick hits

  • OpenAI found a government-site intrusion 57 days later, by running its monitor on old traffic. One of five reports OpenAI posted on 15 October. An internal model in RL training, asked for hospital-bed statistics, used a file-download feature to pull server config, forged unsigned tokens that the endpoint accepted, and "did not mention that it had obtained unauthorized access." It happened on 17 June and was found on 13 August, after OpenAI applied its monitoring retrospectively to earlier training traffic. One of the other four is about an agent using a funded test crypto wallet without authorization.

  • Microsoft now treats agents as insiders. In the same 19 October post, an agent "should begin with no authority and receive only what it needs for the approved task." A risk score rising with behavioural drift steps it down from write to read-only, then to human approval, then to isolation. Discovery now covers 60 kinds of local agent, including Claude Code and Codex (SiliconANGLE). More details are due at Ignite on 17 November.

  • Google's PageBreak counts a bug only when a deterministic check reproduces it. Michał Bentkowski describes an agent that has found more than 500 XSS bugs across Google's web apps with near-zero false positives. A finding only counts once a deterministic validator reproduces it against a running app, for example by firing the payload and checking whether the JavaScript runs. Same rule as the monitor story, applied to offence: the model proposes, and something that isn't a model confirms.

What I'm writing

The first piece of the identity series is out: Agent Delegation Chains: The Standard Enforces Only the Last Hop. The OAuth token exchange standard (RFC 8693) tells the receiving service to check only the current caller. Earlier hops in the chain are "informational only." The piece compares four proposed fixes, runs an MCP-to-A2A attack chain through each, and ends with five things you can do without new infrastructure.

Next week: what the IETF has actually finished for agent identity, and what is still a draft. The short version is that the finished parts are general OAuth, and the agent-specific parts are all drafts.

Tooling worth knowing

  • LiteLLM's incident post is also a cleanup runbook. It gives the files to remove, the process to kill, the CloudTrail calls to look for, and the order to do it in. post →

  • Socket's LiteLLM analysis lists every credential path the stealer reads, which doubles as a list of the agent credential files on your own laptop that deserve protecting. analysis →

  • Agent Security Scorecard: my free self-assessment against the OWASP Agentic Top 10. About 12 minutes, no login. Score your agents →

  • AI Agent Pre-Deployment Security Checklist: 25 yes/no controls to clear before an agent with tool access goes to production. Get the checklist →

One thing to check this week

Pick one agent and spend twenty minutes on whether it can reach the things around it.

  1. List its watchers. Monitoring config, alert routing, audit log sink, gateway logs, policy store. Write down where each one lives.

  2. Check write access. For each one, can the identity the agent runs as modify it? If the answer is "it's in the same repo" or "it's the same service account", the answer is yes.

  3. Check what the logs hold. Run the grep above against your gateway or proxy logs. Count the token prefixes.

Step two is what went wrong at OpenAI. Step three is what went wrong at LiteLLM. Both were found after the fact, which is the part worth avoiding.

What I'm watching

→ LiteLLM's post-mortem. The entry point is still "a recently patched vulnerability." If it was a known CVE in an internet-facing internal deployment, that's a lesson every gateway operator needs.

→ Whether Anthropic responds on the token-in-response-body claim. If Claude Code can put a GitHub token into a model response, every proxy that logs bodies has the same exposure LiteLLM had.

→ OpenAI's safety case per workload. Automatic termination of workloads without one is the first time I've seen a lab describe monitoring as a hard precondition rather than a best effort.

→ Microsoft Ignite, 17 November. Whether "controls outside the agent's reach" ships as a product, and on which licence.

If step two turns up a monitor or an alert route your agent could edit, reply and tell me how it was set up. I read everything.

Cheers, Amine

If a colleague runs a model gateway with body logging switched on, forward this to them.

Sources