A botnet tracked as Carbonato is actively compromising internet-exposed Docker hosts and doing something we haven't seen at scale before: deploying an AI agent — built on the open-source Hermes Agent framework — directly onto victim machines. The agent takes instructions through a Telegram-based command-and-control channel and executes operator commands autonomously on the compromised host. The campaign's monetization angle is equally modern: theft of AI API keys (OpenAI, Anthropic, and similar credentials) stored in environment variables, .env files, and application configs on the Docker host.
This matters for two reasons. First, any organization running Docker with an exposed or weakly protected daemon socket — TCP 2375 (unauthenticated HTTP) or a misconfigured 2376 — is in the target set. Second, the abuse of a legitimate open-source AI agent framework as the post-exploitation payload breaks a lot of assumptions in traditional malware detection. There is no custom implant to signature. The malicious behavior is a legitimate agent binary executing natural-language-derived shell commands under an attacker's control.
If you run containerized workloads that touch the public internet — especially development, CI/CD, or AI/ML environments where API keys are commonly baked into containers — assume you are in scope and start hunting now.
Technical Analysis
What's affected
- Docker Engine hosts with the daemon API exposed to the network — most commonly TCP 2375 (plain HTTP, no authentication) and poorly secured 2376 (TLS, but with weak or missing client cert validation).
- Hosts where the Docker socket (
/var/run/docker.sock) is mounted into containers, enabling container escape to full host control. - Any host storing AI provider API keys in plaintext:
.envfiles,~/.config, shell profiles, Kubernetes secrets mounted as env vars, or CI/CD runners. - The payload is built on Hermes Agent, an open-source AI agent framework, so the binary itself is not inherently malicious — context is everything.
Attack chain
- Discovery: Carbonato scans the internet for Docker daemons listening on 2375/2376. Shodan has indexed tens of thousands of these for years; exploitation is trivial — an unauthenticated request to
/containers/createfollowed by/containers/{id}/startyields code execution. - Initial foothold: The operator creates a new container (often with the host filesystem mounted at
/hostor similar, or with--privileged) and executes a bootstrap command inside it. - Payload deployment: Instead of a conventional miner or ELF implant, the attackers install and configure Hermes Agent, pointing it at an operator-controlled Telegram bot for tasking.
- C2 and autonomous execution: The agent polls Telegram (outbound HTTPS to
api.telegram.org) for instructions and executes shell commands locally — effectively an LLM-driven remote shell. Because Telegram is a legitimate, widely used service, this C2 blends into normal HTTPS egress. - Collection and monetization: The agent is tasked to enumerate and exfiltrate AI API keys — scanning
.envfiles, environment variables (OPENAI_API_KEY,ANTHROPIC_API_KEY, etc.), and config directories. Stolen keys are resold or abused for LLM access billed to the victim. Secondary payloads (cryptominers, additional botnet agents) are dropped opportunistically.
Exploitation status
This is confirmed active exploitation in the wild — a live botnet operation, not a theoretical attack. No CVE is associated with this campaign; it exploits misconfiguration, not a software vulnerability. An unauthenticated Docker daemon on 2375 is root-by-design. That distinction matters for remediation: there is no patch to apply, only exposure to eliminate and hygiene to enforce.
Why this campaign is different
From a detection engineering standpoint, the Hermes Agent payload is a problem. Traditional AV and EDR signature coverage won't fire on a legitimate open-source framework. The detectable surfaces are behavioral: unexpected processes spawned by dockerd/containerd, shells and interpreters egressing to api.telegram.org, mass reads of credential-shaped files, and new containers created via the network-facing Docker API.
Detection & Response
The following detections are grounded in the observable behaviors above. Tune allowlists for your environment before deploying broadly.
Sigma Rules
---
title: Suspicious Container or Shell Spawned by Docker Daemon
description: Detects shells, interpreters, or download utilities spawned directly by dockerd or containerd, consistent with Docker API abuse campaigns such as Carbonato that execute bootstrap commands inside newly created containers.
references:
- https://www.darkreading.com/identity-access-management-security/carbonato-botnet-ai-agent-hacked-docker-hosts
- https://attack.mitre.org/techniques/T1059/004/
author: Security Arsenal
date: 2026/04/06
logsource:
category: process_creation
product: linux
detection:
selection_parent:
ParentImage|endswith:
- '/dockerd'
- '/containerd'
- '/runc'
selection_child:
Image|endswith:
- '/sh'
- '/bash'
- '/dash'
- '/python'
- '/python3'
- '/curl'
- '/wget'
- '/nc'
- '/busybox'
condition: selection_parent and selection_child
falsepositives:
- Legitimate container healthchecks and entrypoint scripts using curl or shells
- CI/CD build agents executing commands inside containers
level: high
---
title: Outbound Connection to Telegram API from Non-Desktop Process
description: Detects Linux server processes establishing outbound connections to api.telegram.org, a strong indicator of Telegram-based C2 as used by the Carbonato botnet's Hermes Agent payload. Servers rarely have a legitimate reason to talk to Telegram.
references:
- https://www.darkreading.com/identity-access-management-security/carbonato-botnet-ai-agent-hacked-docker-hosts
- https://attack.mitre.org/techniques/T1102/002/
author: Security Arsenal
date: 2026/04/06
logsource:
category: network_connection
product: linux
detection:
selection:
DestinationHostname|contains:
- 'api.telegram.org'
- 'core.telegram.org'
- '149.154.'
Image|endswith:
- '/python'
- '/python3'
- '/node'
- '/sh'
- '/bash'
- '/curl'
- '/wget'
condition: selection
falsepositives:
- Legitimate monitoring or alerting integrations that post to Telegram bots
level: high
---
title: Mass Access to Environment and Credential Files on Linux Host
description: Detects processes reading multiple credential-bearing files (.env, shell profiles, cloud and AI tool configs) in a pattern consistent with Carbonato's AI API key harvesting behavior.
references:
- https://www.darkreading.com/identity-access-management-security/carbonato-botnet-ai-agent-hacked-docker-hosts
- https://attack.mitre.org/techniques/T1552/001/
author: Security Arsenal
date: 2026/04/06
logsource:
category: file_event
product: linux
detection:
selection:
TargetFilename|contains:
- '/.env'
- '/.bashrc'
- '/.bash_profile'
- '/.zshrc'
- '/.config/openai'
- '/.config/anthropic'
- '/.aws/credentials'
- '/.docker/config.json'
filter_user:
Image|endswith:
- '/sshd'
- '/systemd'
condition: selection and not filter_user
falsepositives:
- Developer workstations where users frequently edit environment files
- Configuration management tools (Ansible, Chef) reading env files
level: medium
KQL (Microsoft Sentinel / Defender)
These queries assume Docker host Syslog is ingested into Sentinel (via the AMA/Linux agent) and that Defender for Endpoint covers container hosts where possible. The first hunts the Telegram C2 egress; the second hunts Docker API-driven process execution.
// Hunt 1: Server processes egressing to Telegram API (Carbonato C2 behavior)
// Scope: Defender for Endpoint device network events
let timeframe = 7d;
DeviceNetworkEvents
| where TimeGenerated > ago(timeframe)
| where RemoteUrl has_any ("api.telegram.org", "core.telegram.org")
or RemoteIP startswith "149.154."
| where InitiatingProcessFileName in~ ("python", "python3", "node", "sh", "bash", "curl", "wget", "hermes")
or InitiatingProcessFolderPath has_any ("/usr/local/bin", "/tmp", "/var/tmp", "/dev/shm")
| summarize Connections = count(), FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated)
by DeviceName, InitiatingProcessFileName, InitiatingProcessCommandLine, RemoteUrl, RemoteIP
| sort by FirstSeen asc;
// Hunt 2: Shells/interpreters spawned by dockerd/containerd + suspicious docker API activity in Syslog
let timeframe = 7d;
Syslog
| where TimeGenerated > ago(timeframe)
| where ProcessName has_any ("dockerd", "containerd")
or SyslogMessage has_any ("containers/create", "containers/start", "/exec")
| where SyslogMessage has_any ("POST", "exec")
| extend SourceIP = extract(@"(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})", 1, SyslogMessage)
| summarize Events = count(), FirstSeen = min(TimeGenerated), LastSeen = max(TimeGenerated),
SampleMessages = make_set(SyslogMessage, 5)
by Computer, ProcessName, SourceIP
| where isnotempty(SourceIP) // API calls originating over the network, not local socket
| sort by Events desc;
// Hunt 3: Processes reading credential-bearing files (AI API key theft staging)
let timeframe = 7d;
DeviceFileEvents
| where TimeGenerated > ago(timeframe)
| where FileName endswith ".env"
or FolderPath has_any (".aws/credentials", ".docker/config.json", ".config/openai", ".config/anthropic")
| where InitiatingProcessFileName !in~ ("code", "vim", "nano", "sshd", "systemd")
| summarize FileReads = count(), Files = make_set(FileName, 10)
by DeviceName, InitiatingProcessFileName, InitiatingProcessCommandLine
| where FileReads > 3
| sort by FileReads desc;
Velociraptor VQL
This artifact enumerates running processes with Telegram connectivity or Hermes-like execution paths, plus Docker containers with dangerous mounts — useful for rapid triage across a Linux fleet.
-- Carbonato triage: Telegram C2 connections, suspicious processes, and dangerous container mounts
-- Run against Linux Docker hosts
-- Section 1: Processes with established connections to Telegram infrastructure
SELECT Pid, Name, CommandLine, Exe, Username, CreateTime
FROM pslist()
WHERE CommandLine =~ 'telegram|hermes'
OR Exe =~ '/tmp/|/var/tmp/|/dev/shm/|/usr/local/bin/hermes'
-- Section 2: Live network connections to Telegram IP ranges
SELECT Pid, Name, RemoteAddr, RemotePort, Status
FROM netstat()
WHERE RemoteAddr =~ '^149\\.154\\.'
AND Status = 'ESTABLISHED'
-- Section 3: Hunt credential files modified recently (potential theft staging)
SELECT FullPath, Size, Mtime, Ctime
FROM glob(globs=['/root/.env', '/home/*/.env', '/home/*/.aws/credentials',
'/home/*/.config/openai/**', '/home/*/.config/anthropic/**', '/root/.docker/config.json'])
WHERE Mtime > now() - 604800
Remediation & Hardening Script (Bash)
Run this on every Docker host to audit exposure, find live compromise indicators, and apply immediate hardening. Review output before the destructive steps.
#!/usr/bin/env bash
# Carbonato triage + Docker daemon hardening — run as root
set -euo pipefail
REPORT="/root/carbonato_triage_$(date +%Y%m%d_%H%M%S).log"
exec > >(tee -a "$REPORT") 2>&1
echo "=== [1] Docker daemon listening sockets ==="
ss -lntp | grep -E ':(2375|2376)' || echo "OK: Docker API not listening on TCP."
echo
echo "If 2375 is open to anything beyond localhost, this host is exposed. Shut it down NOW:"
echo " - Remove '-H tcp://0.0.0.0:2375' from /etc/docker/daemon.json and systemd unit overrides"
echo " - systemctl restart docker"
echo
echo "=== [2] Containers with host filesystem or privileged access ==="
for c in $(docker ps -q 2>/dev/null); do
docker inspect "$c" | jq -r '
.[0] as $c |
"\($c.Name) | privileged=\($c.HostConfig.Privileged) | mounts=\([$c.Mounts[].Source] | join(",")) | image=\($c.Config.Image)"'
done | grep -Ei 'privileged=true|/var/run/docker.sock|Source.*:/$|/etc|/root' \
|| echo "No privileged containers or host-root mounts found."
echo
echo "=== [3] Processes talking to Telegram (Carbonato C2) ==="
ss -tnp | grep -E '149\.154\.' || echo "No live Telegram connections."
grep -rE 'api\.telegram\.org' /proc/*/cmdline 2>/dev/null | head -20 \
|| echo "No Telegram references in process cmdlines."
echo
echo "=== [4] Hermes Agent / suspicious binaries in writable dirs ==="
find /tmp /var/tmp /dev/shm /usr/local/bin -type f -executable -mtime -30 2>/dev/null \
| xargs -r ls -la
echo
echo "=== [5] Recent suspicious Docker API calls in journal ==="
journalctl -u docker --since "7 days ago" --no-pager 2>/dev/null \
| grep -E 'POST.*/containers/(create|start)|POST.*/exec' | tail -50 \
|| echo "No docker journal entries (check syslog instead)."
echo
echo "=== [6] AI API keys exposed in container environments (rotate these) ==="
for c in $(docker ps -q 2>/dev/null); do
docker inspect "$c" | jq -r '.[0].Config.Env[]?' 2>/dev/null \
| grep -Ei 'OPENAI|ANTHROPIC|API_KEY|TOKEN|SECRET' \
| sed 's/=.*/=<REDACTED — ROTATE>/'
done
echo
echo "=== [7] Hardening: firewall Docker API, enforce TLS-only if remote access required ==="
# Block external access to Docker API ports (adjust to your firewall manager)
iptables -C INPUT -p tcp --dport 2375 -j DROP 2>/dev/null \
|| iptables -A INPUT -p tcp --dport 2375 -j DROP
iptables -C INPUT -p tcp --dport 2376 ! -s 10.0.0.0/8 -j DROP 2>/dev/null \
|| iptables -A INPUT -p tcp --dport 2376 ! -s 10.0.0.0/8 -j DROP
echo "Firewall rules applied. Persist them per your distro (iptables-save / firewalld)."
echo
echo "=== DONE. Report saved to $REPORT ==="
echo "Next steps: rotate every AI/cloud API key found in section 6, and rebuild any"
echo "container created in the last 30 days that you cannot attribute to your team."
Remediation
There is no vendor patch for this campaign — Carbonato exploits misconfiguration and credential hygiene failures. Your remediation plan should be:
Immediate (today):
- Close the Docker API. Audit every host for listeners on TCP 2375/2376 (
ss -lntp | grep -E ':(2375|2376)'). Port 2375 must never be network-accessible — it is unauthenticated root. Remove-H tcp://...flags from/etc/docker/daemon.jsonand systemd drop-ins, then restart the daemon. If remote daemon access is genuinely required, use 2376 with mutual TLS and verified client certificates, or better, SSH-based Docker contexts (docker -H ssh://...) which eliminate the listener entirely. - Hunt for compromise using the detections above. Any container you can't attribute to a known pipeline or engineer is suspect. Check creation timestamps, entrypoints, and mounts.
- Rotate every AI and cloud API key stored on exposed or questionable hosts — OpenAI, Anthropic, AWS, GCP, Azure, GitHub tokens. Assume keys in
.envfiles and container environment variables on a Carbonato-hit host are already sold. Review billing dashboards for anomalous LLM usage spikes — that's often the first visible indicator. - Block Telegram egress from servers. Add
api.telegram.organd the149.154.64.0/20range to egress deny rules for server VLANs and container networks. There are few legitimate reasons for production servers to reach Telegram.
Short term (this week):
- Eliminate dangerous mounts. Remove
/var/run/docker.sockmounts and--privilegedflags from containers that don't strictly need them. Enforce rootless Docker or userns-remap where feasible. - Move secrets out of environment variables and
.envfiles. Use a secrets manager (Vault, AWS Secrets Manager, Doppler) with short-lived credentials. AI API keys are now a first-class theft target precisely because they're sprayed across dev environments in plaintext. - Segment container networks. Docker hosts in dev/CI should not share flat network access with production or secrets infrastructure.
Strategic:
- Treat exposed Docker daemons as a standing misconfiguration in your CSPM/attack-surface management tooling. Continuous external scanning for 2375/2376 on your IP ranges should be table stakes — the attackers are scanning constantly, so your visibility must be too.
- Deploy runtime security (Falco, or equivalent eBPF-based detection) on container hosts with rules for shells spawned by container runtimes and unexpected egress. The Sigma rules above can be adapted as Falco rules for runtime-layer coverage.
- Update threat models for agentic payloads. Carbonato demonstrates that AI agent frameworks are now off-the-shelf post-exploitation tooling. Your SOC playbooks should treat legitimate AI/agent binaries found on servers as investigation-worthy — presence plus network egress plus credential access is the detection triad, not the binary's signature.
Related Resources
Security Arsenal Penetration Testing Services AlertMonitor Platform Book a SOC Assessment vulnerability-management Intel Hub
Is your security operations ready?
Get a free SOC assessment or see how AlertMonitor cuts through alert noise with automated triage.