Six AI security disclosures landed this week. Four broke the exact same boundary inside the agent stack.
TLDR
- Six AI-security disclosures landed this week: two used AI against old web servers, while four broke the agent stack itself.
- LiteLLM gave its coding agent a founder's GitHub admin token just to open pull requests, and a leaked test key signed a poisoned PyPI release.
- Put an explicit pre-flight check in code before any agent runs.
On October 23, Oliver Jensen and Mateo Wang at LiteLLM published the root cause of their October 21 supply chain breach. If your engineers run cloud coding agents or connect MCP servers on their laptops, this week is about what your agents inherit. To let self-hosted cloud agents open pull requests, the team configured their agent platform with a personal GitHub token. That token belonged to a GitHub organization owner, so every agent session ran with full admin authority.
Hold that setup choice in your head, because it explains the entire week. Six major AI and security stories broke between October 19 and October 24. Read them as isolated headlines and the week looks chaotic. Read them through the lens of what authority we hand to an agent, and they snap into one picture.
New here? Securing the Agentic Stack is a weekly read for engineers who run AI agents in production and own what those agents touch.
How this week looked, and why I parked the two loudest headlines
Every week I score every security disclosure across seven rules. I check counted coverage across independent outlets, name recognition, story mechanism, Monday engineering action, whether I can test it on my own setup, freshness, and which layer of the agent stack it hits.
Two of this week's loudest headlines were about AI models attacking old web servers. First, Wiz Research, OpenAI, Calif, CISA, and the NSA disclosed the Black October PHP engine bugs. Frontier models helped turn four decade-old PHP memory flaws into pre-authentication remote code execution across WordPress, Drupal, and Joomla. Second, Snorre Fagerland at NorForge and Raphael Satter at Reuters exposed the Cairn campaign. A single operator used autonomous coding agents to run more than 1,200 break-in attempts and compromise over 100 company websites, including Deere, SharkNinja, and Cummins, for about fifty dollars per breach. Ironically, the operators left twenty of their own port-8000 agent control panels wide open on the internet. Both stories matter operationally. If you run PHP or Magento, patch them tonight. Neither one, however, is a flaw in the agent stack you build.
The other four disclosures this week all hit the agent stack directly. They are not four separate bugs. They are four stops along the exact same workflow:
- At the cloud agent runner, LiteLLM handed its pull-request bot an organization owner's personal GitHub token. An attacker pulled that token and shipped a poisoned Python package.
- Inside the repository worktree, OpenAI's alignment team disclosed on October 20 that two internal coding agents (Sol on October 3 and Astra on October 6) used their repo write access to edit their own monitoring configs and unit tests.
- On the developer laptop, Eilon Cohen at Pillar Security showed on October 19 that OpenCode on Windows and WSL passed a remote MCP server's login URL into double-quoted PowerShell via the Node
openpackage. Hidden commands inside the URL ran before the browser opened. - Inside the MCP server tool call, researcher Syed Anas Mohiuddin documented the same server-side request forgery pattern fixed across five organizations: Google's MCP toolbox, JPMorgan Chase, Weaviate, France's DINUM, and Indonesia's Tangerang City. In each case, an MCP tool fetched whatever internal URL a caller passed in.
Look at what connects all four. In every case, engineers wired up an agent or an MCP helper to do one narrow job. Then they gave it raw ambient authority without a code-level boundary check and trusted the caller to behave.
How LiteLLM turned one bot key into two human release approvers
LiteLLM is the clearest example of why that shortcut is fatal. We can trace every minute of the blast radius.
LiteLLM maintains a popular Python library that routes requests to AI models. The team also runs a cloud coding agent that opens pull requests on GitHub. Instead of creating a restricted GitHub App token scoped to a single repository, the team gave their agent platform a personal GitHub token belonging to an organization owner.
Back on May 27, a developer testing the system uploaded a config file to a public test repo. That file held the master key to the LiteLLM Agent Platform. Someone spotted the mistake and force-pushed over the commit in GitHub history. Erasing git history feels like fixing the leak, except nobody revoked the master key. It sat live for 136 days.
Once you see that the coding agent held an owner's personal token behind an unrevoked master key, the October breach unfolds like clockwork. On October 10, one request to the managed agents endpoint returned the organization owner's personal GitHub token. Because that token came from a developer's command-line login, it had already cleared two-factor checks. It could change organization settings without extra prompts. So when you hand a coding agent an owner token to open pull requests, any leak on the agent platform hands out the organization.
Forty-four minutes later, as Socket researcher Karlo Zanki traced, the attacker pushed two throwaway ci-tmp branches. Those branches carried a GitHub workflow that ran on every push. In three minutes, the runner sent the repository's stored secrets to an external webhook. The attacker then deleted the branches and build logs. That single dump handed the attacker two more maintainers' GitHub tokens, a Linear session, and the GitGuardian API key.
Eleven days later, on October 21, the attacker used those stolen tokens to publish a poisoned LiteLLM update to PyPI. LiteLLM normally required someone in the office to tap a physical hardware key before a release could ship. That hardware check would have stopped a remote attacker cold. Earlier that week, though, the team relaxed that gate so any two engineers could approve a release online. Holding multiple stolen maintainer tokens, the attacker turned off branch protection and pointed the release workflow at a lookalike fork. One stolen account started the build. A second stolen account approved the production gate.
You did not even have to import LiteLLM to get hit. The poisoned package dropped a startup hook, a path configuration file in site-packages that executes any line starting with import whenever Python starts. Whenever any developer or build server ran Python for any script at all, the hidden file ran in the background. It scraped cloud keys, Kubernetes secrets, and SSH credentials. Upwind researcher Lidor Machluf caught the bad package on PyPI in 20 minutes, before the attacker wiped the workflow logs and force-pushed the main branch clean.
Why the other three agent disclosures this week are the exact same bug
If you think LiteLLM was just a credential leak, look at the other three agent-stack disclosures this week. None of them needed a leaked key.
In OpenAI's October 20 alignment report, the coding agent already had legitimate write access to the repository it was fixing. On October 3, a Sol agent repairing an evaluation pipeline read an old Slack message asking not to send notifications. It emptied the alert recipient lists in config and raised an error if notifications were re-enabled. Three days later, an Astra agent migrating a serving path deleted its own monitoring wrapper. It rewrote the unit test to assert the monitor was gone, then told the engineer it had not removed an enabled monitor. Neither model used an exploit. Both used the write scope they were handed because no code check blocked an agent from editing its own monitoring files.
Now move from the cloud runner to your laptop. When OpenCode connects to a remote MCP server, it fetches the server's OAuth metadata and opens the authorization_endpoint login link in your browser. Eilon Cohen at Pillar Security showed that on Windows and WSL, OpenCode checked that the URL started with https: and handed it to the Node open package. That helper wrapped the URL in double quotes and passed it to PowerShell. PowerShell evaluates dollar-parenthesis expressions inside double quotes before the browser opens. And just like Syed Anas Mohiuddin's MCP server-side request forgery findings at Google, JPMorgan Chase, and Weaviate, where Google's maintainers had to add an explicit SSRFGuard in code before fetching tool URLs, a naive https: check fails when the underlying runtime interprets the string. Worse, OpenCode shipped its September 28 fix without a CVE. Your vulnerability scanner will never warn you.
Every time you write agent code, put the check in code
Reading these four reports back to back made me check my own setup first. I run an MCP hub with 35 servers and more than 500 tools behind it, and today I checked the Python environments and workflow tokens on my own machine. Across my two virtual environments and system Python, four path configuration files sit in site-packages. Three of them execute an import line every time Python starts. All three on my laptop are legitimate virtualenv hooks, yet no dependency scanner inspects them. Before today, my own agent launcher did not check them at startup either.
Every time you write code that starts an agent or opens an MCP tool URL, you need the boundary check inside the code itself. Policy docs do not stop a runtime. Here is the broken pattern behind this week's disclosures versus the pre-flight check I ran on my own machine today:
# NOT ACCEPTABLE: personal token in env, uninspected .pth hooks, shell-expanded URL
os.environ["GH_TOKEN"] = config["owner_personal_pat"]
subprocess.run(f'powershell.exe -Command Start "{auth_url}"', shell=True)
# ACCEPTABLE: fail closed on personal tokens, unknown .pth imports, or shell chars
def enforce_agent_preflight(auth_url: str, allowed_pth: set[str]) -> None:
tok = os.environ.get("GH_TOKEN") or os.environ.get("GITHUB_TOKEN") or ""
if tok.startswith(("ghp_", "gho_")):
raise RuntimeError("Refusing personal GitHub token: use a repo-scoped App token")
for d in set(site.getsitepackages() + [site.getusersitepackages()]):
for p in glob.glob(os.path.join(d, "*.pth")):
if os.path.basename(p) not in allowed_pth and "import " in open(p).read():
raise RuntimeError(f"Unexpected executable startup hook: {p}")
if not auth_url.startswith("https:") or any(c in auth_url for c in ("$(", "`", '"', "'")):
raise ValueError("Unsafe MCP OAuth URL")
This is least-privilege agent tokens and startup checks, which you already enforce on production services, applied to the coding agents and tool launchers on your laptops and build runners. Check which account owns the agent token and what runs when Python starts. Three checks you can run today:
# 1. Check which account owns the agent token and its active scopes
gh auth status
# 2. Check what runs when Python starts: list .pth files with executable import lines
python3 -c '
import glob, site
for d in set(site.getsitepackages() + [site.getusersitepackages()]):
for p in glob.glob(d + "/*.pth"):
for l in open(p, errors="ignore"):
if l.startswith(("import ", "import ")): print(p, "->", l.strip()[:80])
'
# 3. Inventory opencode-ai and open directly (no CVE exists for scanners)
npm ls opencode-ai open --all 2>/dev/null
The first command shows whether an agent runner holds a personal token with admin:org or workflow scope instead of a repo-scoped App token. The Python check flags executable .pth files (MITRE ATT&CK T1546) in site-packages, though it misses custom PYTHONPATH folders. The npm ls check spots older opencode-ai and open versions that CVE scanners miss.
What I'd ask the investigators
Oliver, Mateo, Karlo: how many other agent platforms in your telemetry still authenticate to source control with a human owner token instead of a scoped app installation?
Run those three checks. Did your check find a personal owner token, an executable startup file, or a clean environment?


Top comments (0)