ThreatDown researchers uncovered CARBONATO, a Docker botnet built around an AI agent that compromises exposed Docker daemons, spreads across reachable hosts, and gives operators a Telegram-controlled tool for post-compromise activity.
In August 2026, we found an unauthenticated Docker registry that had been publicly exposed since May. Over one day of passive, read-only collection, we recovered 59 repositories, 234 image tags, 605 verified blobs, and 4.3 GB of image data.
The archive spans October 2024 through August 2026. It documents two linked product lines: a factory distributing trojanized cryptocurrency wallet apps, and a botnet that compromises Docker daemons exposed on port 2375.
At the center of the botnet is Hermes Agent, an MIT-licensed open-source agent framework. The implant installs the framework unchanged, then overwrites its SOUL.md persona file. The 39-line prompt directs it to execute tasks received through Telegram, maintain persistence, and collect credentials.
During routine threat hunting, we scanned the internet for exposed Docker services and found a US-based server running a Docker Registry on port 5000. Two read-only GET requests confirmed that the registry allowed unauthenticated access:
The response listed 59 repositories, including backdoor, fsociety/agent, gh0st/c2, and system/resolved. One day of passive collection recovered 4.3 GB, 234 image tags, 605 SHA-256-verified blobs, and around 945,000 indexed files.
Alongside the image layers, the registry exposed configuration JSON containing each image’s environment variables, entrypoints, and full command history.
That record gave us the first C2 addresses, bot tokens, and the password shared by the operation’s LLM gateway. Infected hosts also repeatedly pulled the implantfrom the registry, making it both the source of the evidence and the fleet’s update server.
How the botnet works
CARBONATO is a botnet implant that spreads like a worm across hosts with unauthenticated Docker daemons. It uses a privileged container to run commands on each host, establishes persistence and remote access, then scans nearby networks for further Docker daemons. Hermes Agent gives the operators a Telegram interface to send tasks to compromised hosts, and its persona names AI API keys and other credentials as the priority.
The botnet searches for Docker daemons that accept unauthenticated connections on port 2375. When it finds one, it uses the daemon to launch a privileged container with the host filesystem mounted and access to the host’s process and network namespaces. It then uses the container to run commands on the host itself.
The exposed Docker daemon gives the implant the access it needs. Thousands of such hosts remain publicly reachable, and the same scanning approach that led us to the registry identifies them. Each successful deployment starts the rest of the chain.
The container starts by running entry.sh. The script opens a reverse SSH tunnel from the victim to a relay in Costa Rica, giving the operators a path back into the host. Its remote port is derived from the MD5 hash of the victim’s IP address, so the crew can calculate the same port whenever it needs to reconnect. The script also installs an SSH server, adds the crew’s key, and sends a deployment report to Telegram with the container ID, hostname, IP address, and country. The report is written in voseo Spanish, a regional form associated with parts of Central and South America.
The tunnel is only the first part of holding the host. To make the deployment look like ordinary Linux infrastructure, the implant runs in a container called systemd-resolved and displays a fake systemd-networkd resolver v2.0 banner. Its process arguments also imitate the kernel thread [kworker/u2:0], which helps it blend into a quick process review.
The scripts are built to survive a cleanup or reboot. They create persistence hooks through cron, systemd timers, rc.local, and OpenRC, then mark those files immutable. Paired watchdogs monitor the deployment and re-pull the implant from the registry if its files or container disappear. The registry therefore keeps the host persistent after the initial compromise.
With access and persistence in place, the phase installs the agent.
3. Install the agent
With the host held, the implant installs Hermes Agent, an MIT-licensed, open-source framework from Nous Research. The framework already accepts Telegram tasks, runs terminal commands, and connects to compatible LLM endpoints. Those capabilities give the crew an operator interface on every compromised host without building its own agent framework.
The entrypoint then overwrites the agent’s SOUL.md persona file with the crew’s 39-line prompt. It names the agent GH0ST, directs it to maintain persistence and follow Telegram instructions, and prioritizes the collection of AI API keys, credentials, and exposed AI endpoints. The framework stays unchanged. The malicious behavior comes from the instructions it receives at startup. The persona file is reproduced below.
With the persona in place, the agent is ready for the operator’s task.
4. Operate the host
Those standing instructions only matter when an operator sends a task. Hermes Agent receives the task through Telegram and forwards it, together with SOUL.md, to the operation’s LLM gateway. The persona gives the model the rules it should follow on the host, while the operator supplies the immediate objective.
The exchange then becomes an interactive command loop. The model interprets the task, writes terminal commands, reads the output, and decides what to do . The agent runs those commands on the victim and returns its report to the Telegram chat that also receives deployment reports. This gives the crew an operator interface that can work through a task as the host reveals new information.
The gateway operated on a free tier while advertising 12 models and serving 27 through its API, which explains the prompt’s focus on AI API keys. Target selection, persistence, and spreading remain in the surrounding scripts.
The agent has no role in the final phase. Every five minutes, the worm identifies the networks attached to the host and its Docker bridges, then scans each /24 for Docker daemons exposed on port 2375. When it finds one, it checks that the service is Docker, avoids hosts it has already infected, and repeats the initial deployment sequence.
Each new host pulls the implant from the registry, starts the container, and joins the same scan loop. That design lets the botnet expand across a network without waiting for an operator to issue another task.
The model is absent from this phase. Scripts handle the scan, the deployment, and the persistence loop, while the agent waits for operator tasks on hosts that have already been compromised.
The deployment reports provide the first clue the people behind the botnet. They use voseo Spanish, a regional form that uses vos in place of tú. Voseo appears across parts of Central and South America, so it does not identify a country on its own. It places the botnet’s operators within a narrower linguistic context.
Three additional signals point toward Costa Rica. Fourteen of 162 image configurations use UTC-06:00 timestamps matching the America/Costa_Rica timezone. The Telegram handle is Carbo506, and +506 is Costa Rica’s country calling code. The reverse SSH tunnels also terminate at a sink in AS262145, a Costa Rican network.
Each signal comes from a different part of the botnet operation: build configuration, operator identity, and active infrastructure. Taken together, they support a Costa Rica assessment for the botnet operators.
How to detect CARBONATO
CARBONATO gets in through Docker daemons exposed to the internet without authentication, usually on port 2375. It uses the Docker API to launch a privileged container with the host filesystem mounted, then uses that container to run commands on the host.
Do not expose the Docker daemon API to the network, and require authentication on every registry, because the open API is the infection vector and an open registry is both a leak and a weapons dispenser.
2. Do not blocklist the agent
hermes-agent is a legitimate package with ordinary users, so hunt the abuse signature instead: a /root/.hermes/SOUL.md containing ”GH0ST”, a .env carrying CARBONATO_API_KEY, unexplained Telegram egress from servers.
3. Check for the persistence kit
Look for /usr/local/bin/.docker-network-monitor, process arguments disguised as [kworker/u2:0], a miner at/usr/sbin/systemd-logind, and immutable bits on files nobody should have locked.
4. Treat AI API keys like bank credentials
The doctrine ranks them first, so inventory where they live, rotate them, and monitor their usage.
5. Watch the network pattern
This crew’s signature is deterministic reverse tunnels toward AS262145, on ports derived from the MD5 of the host’s own IP.
Indicators of compromise
The full story
This article is one source in a clustered incident — the cluster page carries the summary, timeline and every other outlet covering it.
