DEV Community

Cover image for AI Agents Broke Into 100+ Sites at About $50 Each. The Confirmed One Used Old PHP Flaws
Gabriel Anhaia
Gabriel Anhaia

Posted on AI-assisted

AI Agents Broke Into 100+ Sites at About $50 Each. The Confirmed One Used Old PHP Flaws


One operator, fewer than 100 Chinese characters of instructions, and roughly $5,000 in tokens. By the estimate Reuters reported on October 19 (via BNN Bloomberg), that was enough for AI agents to break into websites belonging to more than 100 companies, at around $50 in tokens per successful hack. The same day, the security firm NorForge published Inside Cairn, a report on more than 20 AI "hacking" control panels it found sitting open on the public internet.

Reuters named Deere, SharkNinja and Cummins among the victims. Deere said it had taken remediation actions and saw no sign that sensitive data was accessed. SharkNinja said a standalone product-support site was hit and the threat contained. Cummins said it was investigating a report of a potential attack on a website run by one of its third-party vendors.

The detail that matters more for you is how they got in. NorForge verified one intrusion by fetching the web shell the agents left behind. By the agent's own log, that break-in used no new or clever exploit. It ran through a memcached session store the attacker could write to, an unsafe PHP unserialize() call, and a gadget chain in legacy Zend Framework components. Each of those has been a known footgun for years.

A control panel on port 8000, open to anyone

The tool in the story is Cairn, an open-source "general-purpose problem-solving engine" that was first validated on autonomous penetration testing. It is AGPLv3, it runs coding-agent CLIs like Claude Code, Codex and Pi as its workers, and its README is explicit that you must have "clear prior permission from the owner or operator" before pointing it at anything. It is a red-team tool with legitimate uses.

What NorForge documents is operators leaving the tool's web panel exposed. It found the panels by scanning with Shodan and Censys, grouped them into three clusters by shared targeting and instructions, and assessed all three as malicious, two with high confidence. Every panel in its indicator list was reachable on port 8000. Some were protected against unauthorized access; others "appear completely unprotected," showing what looked like full administrative control to anyone who browsed to the address.

Docker is one common way this happens. Cairn's own Docker Compose setup starts its server on port 8000, and Docker's docs warn that publishing container ports is insecure by default: a plain -p 8000:8000 publishes to all host addresses (0.0.0.0 and [::]), so the port "becomes available not only to the Docker host, but to the outside world as well," and your laptop is only one of the machines that can reach it. The fix is one prefix:

# Reachable only from this machine
docker run -p 127.0.0.1:8000:8000 my-agent-panel
Enter fullscreen mode Exit fullscreen mode

However these operators exposed theirs, the result was the same: NorForge read much of their operation off the open panels, down to the target lists and the agents' own notes on what they found.

The one verified break-in used old PHP

NorForge was careful not to claim it broke into anything. To check that one claimed intrusion was real, it fetched the URL of an "uploader" web shell the agents had left on a large hardware-parts vendor, and the shell was there. The report does not say NorForge used it. The account of how the agents got in comes from the agent's own explanation in its task log.

The chain, as that log tells it: the agents found a memcached session store they could write to, poisoned a serialized session value, and triggered PHP object injection through a gadget chain in legacy framework code. memcached's own docs say plainly, "you must not expose memcached directly to the internet, or otherwise any untrusted users," and add that the server spends little, if any, effort defending itself from random internet connections. PHP's unserialize() manual opens with a warning: "Do not pass untrusted user input to unserialize() regardless of the options value of allowed_classes." PHPGGC, a public library of ready-made unserialize() payloads that includes Zend Framework chains, was among the tools NorForge found in an agent worker folder.

What was new was who did the trying. In NorForge's main cluster, projects that reached their goal took "a little under 23 hours" on average from start to goal, and each project logged around 140 facts on average, grinding through a target until a boring flaw lined up.

Why your unserialize() and your memcached are the target

The pattern to defend against is a shop whose oldest code still trusts its own serialized data. To close the door NorForge described:

  • Never unserialize() untrusted bytes. Session values read back from a shared store count as untrusted the moment that store is reachable by anyone else. The manual's own advice is to move to a format with no object instantiation: json_encode() / json_decode(). Setting allowed_classes => false is not a fix; php.net tells you to keep untrusted input away from unserialize() "regardless of the options value of allowed_classes."
  • Don't expose your session store. memcached and Redis bind where you tell them to. Keep them on 127.0.0.1 or a private network, and treat any internet-reachable cache as already compromised.
  • Retire the legacy framework code that carries the gadgets. The gadget chain lived in old Zend Framework components. Gadget chains come from what your framework leaves on the autoload path, so code you no longer use stays attack surface until you delete it.

Decoupling pays off on the last one. When your domain logic sits behind a thin port instead of inside framework classes, a dead framework version is a dependency you can remove with a composer change and a few adapters, and the rest of the app does not notice.

Don't put your own agent panels on the open internet

There is a direct lesson for anyone running coding agents, even if nobody is targeting you. Cairn's workers are the same CLIs many of us run every day. DeepSeek even documents pointing Claude Code at its own API by setting ANTHROPIC_BASE_URL, which fits the worker name NorForge saw, claudecode_deepseek-v4.1-flash, and Reuters' report that the campaign used a mix of DeepSeek and Claude Code.

So the surface that got these operators caught is the same surface you create when you stand up any agent control plane, task queue or run dashboard and forward a port to "just check it from my phone." Keep it on localhost, behind a VPN or an authenticating proxy. Assume anything on 0.0.0.0 will be indexed.

I build Hermes IDE, so weigh this with that in mind. Hermes is a desktop app: each agent runs in its own terminal and each task on its own hermes/<name> branch and worktree. It is free and source-available (BSL 1.1), on macOS, Windows and Linux. None of that is a security guarantee, and the point stands for whatever you run.

What actually changed

The techniques in this story are a decade old. The economics are not. Reuters reports the agents went after more than 1,200 sites largely without human intervention, with the operator doing almost none of the work. NorForge estimates the average cost of a single task at about $5, counting the failures, and the overall success rate at around 10%, and says the cost figure carries considerable uncertainty.

A 10% hit rate is fine for a loop that costs $5 a swing. The boring flaw you deprioritized because "who would bother" is now worth bothering with, at volume, by something that does not get tired.

NorForge also found hundreds of secrets in the exposed panel data, with Trufflehog verifying 11% as still valid. And it found that legitimate red teams had put real customer penetration tests on unsecured panels of their own.


If this was useful

The flaw in this story was legacy framework code that still trusted its own serialized data. You keep that kind of code from becoming load-bearing by keeping the framework at the edge: domain logic behind ports, framework classes as adapters you can swap or delete. Decoupled PHP covers clean and hexagonal architecture for PHP applications that outlive their framework, which is how an old Zend component ends up as a composer change and a few adapters instead of a migration project. If you also run coding agents, Hermes IDE (GitHub) gives each one its own terminal and its own branch.

Decoupled PHP — Clean and Hexagonal Architecture for Applications That Outlive the Framework

Available on Kindle, Paperback, and Hardcover. English, German, and Japanese editions out now — Portuguese and Spanish coming soon.

Top comments (0)