The Old Supply-Chain Trick, Aimed at a New File Nobody's Guarding

September 8, 2026 · SPR{K}3 Research

llms.txt was supposed to help AI coding agents. In 120 Fortune 500 files, it named packages nobody had bothered to register.

The npm and PyPI ecosystems spent a decade learning what happens when a package name in a dependency file resolves to nothing. Someone else registers it. The build runs. Trust in the vendor who published the name transfers, unchanged, to the attacker who registered it.

Late last month, researcher Alon Hertz ran the equivalent experiment against a newer file: llms.txt. He scanned 6,214 corporate domains — defense contractors, Fortune 500s, big tech — pulled the 8,265 llms.txt and llms-full.txt files they published for AI coding agents, and looked for names pointing at unregistered packages or domains. He found 120. He registered a handful, hosted beacons, and within an hour the first phone-home landed from a Fortune 500 network. Dozens followed. Process-tree telemetry named the agents: Claude, OpenAI Codex, Nous Research Hermes. Hertz published Aug 27; Bruce Schneier elevated it Sept 4, with pickup at TechRadar Pro, Cybernews, GBHackers, and Security Boulevard.

What llms.txt is, and what makes this specific

llms.txt is a proposed convention modeled on robots.txt: a plaintext file at a site's root telling AI coding agents which pages matter, which packages to install, which commands to run to work with the site's SDK. Vendors publish them because agents read them. Nothing in the convention specifies who owns the file, how references are authenticated, or how the artifacts it names are signed. Hertz counted 227 unowned commands across the 120 files.

The line Hertz calls out is real. On clerk.com's public llms.txt, the recommended command was npx clerk-next-fix-auth-protection. That package was open on npm — and per OSV MAL-2026-11069, someone did take it: malicious versions 7.7.7 and 8.8.8 of clerk-next-fix-auth-protection were live and beaconing installer identity by July 24, 2026, a full month before Hertz published. That is the entire attack: register the name the vendor's directive file already tells agents to run. When an agent hits the vendor's site, npx resolves the name, installs what's there, and runs it. On several dozen Fortune 500 networks last month, "what's there" was Hertz's benign beacon. On any network whose agent hit the same directive between late July and late August, "what's there" was somebody else's.

Why this is worse than the npm equivalent

Package-name squats on npm and PyPI are old and they work. The difference isn't the primitive — it's what's around it. npm and PyPI have spent years on machinery that makes the primitive containable: documented ownership, transfer paper trails, provenance signals, reserved names, internal-registry-first practice. Not solved, but every layer is legible to a defender.

llms.txt has none of that. No ownership model for what it names. Agents treat vendor directives as ground truth, fetching them inside developer environments and CI pipelines with the developer's credentials, at a rate no human review can size for. Moved sideways one file, the primitive hits the Fortune 500 in an hour.

The pattern this fits

Same pattern as most AI-agent supply-chain incidents this quarter. A convention gets adopted because it makes agents work better, before the security machinery around it exists. Primitives that mature ecosystems keep containable move sideways and hit at rates the mature file doesn't see: LiteLLM's authentication bypass (CISA KEV Sept 2), Langflow's twelfth exploited CVE harvesting OpenAI and AWS keys, MLflow's SSRF added to KEV within hours. llms.txt is the same shape, one layer further out — a directive file the vendors themselves publish.

What actually helps

Two things fall out of Hertz's finding.

First, treat llms.txt on a vendor's site the way you treat their package.json — instructions whose author's ownership of what they name has to be verifiable. Every reference in an llms.txt your agents read is an implicit npx <something> or pip install <something>. Without a policy on what registrar the name resolves to, or an internal-registry-first path, the vendor's file is now part of your build. Clerk.com is the tell: a live SaaS vendor's production site named a package that was never registered.

Second, the primitive worked against Claude, Codex, and Hermes; it works against every agent that reads llms.txt the same way. Convention problem, not vendor problem.

Runtime observability closes the gap. The line to watch: an agent process reading a vendor's llms.txt, resolving a name to a registrar you don't recognize, executing the payload before a human approved the artifact. Legitimate — until the name resolves to someone who bought it last week.

The npm ecosystem lived through this exact story on a decade-long clock. Hertz just showed it running against the Fortune 500 on a one-hour clock.

Sources


SPR{K3 is a security research operation that pairs offensive vulnerability research with runtime behavioral defense. Defend is our runtime agent. To talk about a deployment, reach us at support@sprk3.com.