november 2026 · 4 min

Your Agent Installs From Memory

Ask a coding agent to "set up a GitHub MCP" and it may write down a package name it learned in training. That name can point at a server archived last year, with known bugs nobody will fix. Glow Labs published this today as MCPhantom, and I've read it through Help Net Security's coverage, not the full report.

Among sessions where a deprecated @modelcontextprotocol server got installed or suggested, Glow says the name came from the model's training data 98% of the time. In the other 2% the user asked for it. That is the share of bad sessions, not of all sessions, and the distinction matters.

The rest of the numbers explain why it isn't rare. server-github still gets about 185,000 npm downloads a week. The deprecated packages have passed 17.3 million npm downloads since July 2025. Glow reports four high-severity flaws, one of them a remote code execution in the Puppeteer server reachable through prompt injection. Its report was closed as out of scope, there are no CVEs, and no exploitation has been seen so far.

The model's memory is now a package source, and it's one you have no lockfile for.

Every Control We Built Distrusts the New

I've argued for consumer-side hashes and release cooldowns. They work because a typical supply chain attack is a fresh malicious version, so pinning and waiting beat it.

This goes the other way. server-github was last published in April 2025, according to this migration guide. It clears any cooldown you can configure. A pin locks you onto the same abandoned code. The publisher wasn't compromised and the hash is fine, because the package is exactly what it says it is.

The other layers miss it too. The server runs through npx from an MCP config, so it never lands in a manifest and dependency scanners have nothing to read. To endpoint tooling it's a trusted Node process fetching a public package.

Reading the warning doesn't save you either. npm deprecation doesn't block an install, and in one of Glow's sessions the agent saw "This package is deprecated", installed anyway and didn't mention it.

The Check

Start by finding out what you already have. This lists every reference server named in the usual MCP configs, minus the npm ones still maintained:

grep -ohE '@modelcontextprotocol/server-[a-z0-9-]+' \
  ~/.claude.json ~/.cursor/mcp.json ~/.codex/config.toml \
  .mcp.json .cursor/mcp.json 2>/dev/null | sort -u |
  grep -vE 'server-(everything|filesystem|memory|sequential-thinking)$'

Anything it prints deserves a look, and the guide above maps most of them to the service owner's own server: github/github-mcp-server for GitHub, microsoft/playwright-mcp for Puppeteer. Run it in each project, since .mcp.json and .cursor/mcp.json are relative paths.

Then make it a gate. Glow's advice is one approved server per service, with deprecation status part of the approval. I'd enforce that where the agent can't talk its way past it, at the point of install, instead of adding a line to a rules file. A rule telling the model which names are stale is a list you'd maintain forever, and it's steering around something the next model may already know. New models will know newer names, but I think training data will always trail the registry, so a gate keeps working where a better memory runs out.

The Tradeoff

An allowlist is friction, and people will run a server by hand to get around it. Some swaps aren't clean: server-postgres has no official successor, so someone has to pick and own a replacement. And this is one vendor's research, read secondhand and with nothing exploited yet, so treat it as a hole to close and not an incident.

None of this is the long-term shape. My bet is that agents get an environment built around what they need, where which server they use isn't a name recalled from training and typed into a config file. Until then, the check above takes a minute, and supply chain problems like this one mostly wait for someone to take that minute.

← all posts