A financially motivated Italian-speaking operator has compromised more than 3,000 servers since April with PoeLLM malware that hides its command-and-control address inside a GitHub-hosted poem. The campaign, named Canto Incognito, focuses on internet-facing AI services including LiteLLM and Ollama, plus Gotenberg, Gitea and Ivanti Sentry affected by CVE-2026-10520, primarily in the US and Western Europe. Infected hosts mine cryptocurrency with XMRig and Iron miners through Kryptex mining infrastructure and are reused as scanners to expand the botnet, peaking at more than 800 active servers per day.
Campaign scope and targets
PoeLLM has been active since at least April and continues to infect new victims. Tracking by Lumen's Black Lotus Labs counts more than 3,000 servers impacted, primarily located in the US and Western Europe.
Most victims were running vulnerable, internet-facing versions of LiteLLM and Ollama. Additionally, hundreds of victims were running Gotenberg, a PDF converter, and software development platform Gitea.
The operator may also have pursued commercial software including Ivanti Sentry. Investigators first encountered PoeLLM while looking into Ivanti Sentry vulnerability CVE-2026-10520. In early June 2026, a compromised Ivanti Sentry victim contacted a dedicated server at 5.78.73[.]122. Shortly after contacting this C2, the Ivanti Sentry victim began scanning for other vulnerable devices.
Attribution rests on Italian language comments within the malware and on the attacker's GitHub pages, plus netflow analyzed by Black Lotus Labs suggesting the attacker is located in Italy. Researchers assess the campaign targets AI systems and assess the poem itself was written by AI. This is described as the first observed real-world use of adversarial poetry, an AI jailbreak technique that turns harmful prompts into poems to trick LLMs into bypassing safety guardrails.
For context, another 2026 incident, the LiteLLM supply chain compromise, focused on a single service and impacted roughly 2,500 victims, according to open sources. That LiteLLM supply chain attack began with a compromised Trivy build and potentially exposed more than 2,500 companies and 434,000 CI/CD pipelines worldwide, according to CloudSEK security researchers. By contrast, the collection of more than 3,000 PoeLLM victims appears to exhibit multiple vulnerable services at any given time. Details on the earlier LiteLLM incidents are in Mercor among thousands hit in LiteLLM attack and LiteLLM infected via Trivy.
Beyond mining on compromised GPU hardware powering AI workloads, PoeLLM converts victims' machines into vulnerability scanners and exploit servers, enabling further compromise.
Poem-encoded C2 mechanism
Investigation links the cryptojacking operator to GitHub user ejejejdfbbebe. That account made the first GitHub commit with the adversarial poem on April 13. The repo is a fork of the nodejs.org website source code, and the file is called dash.css. Inside the file is a poem titled On the Nature of Connection, which has been updated 11 times since its initial commit. The most current version, as of September, is:
In the silent hum of driver, the machines begin to speak,
Each pulse of diode threading light through copper veins.
we taught the dark to carry meaning, byte by byte —
A language built from lightning, cold and clean.
Beyond the wall of encryption, a signal finds its way,
the tick of distant servers answering back.
Data moves like water through the cracks of ordered thought,
and somewhere in the code, the world stays on track.
The malware derives its current command-and-control server from keywords in the poem. When the operator edits the poem, infected systems locate the new C2 location. It parses the poem, extracts certain words and phrases, then converts them to numbers using a hard-coded dictionary in the body of the malware.
Black Lotus Labs describes the C2 discovery logic as:
The function extract_poem_phrase_field extracts three words/phrases from the body of the poem, case-insensitively:
- Word 1: text between
In the silent hum ofand, - Word 2: text between
each pulse ofandthreading - Word 3: text between
Beyond the wall ofand,
0x44a8db–0x44a99b extracts the fourth word differently:
- Walk backward to the previous whitespace
- Require the 4 bytes before the word to be
the
The four words are then matched to corresponding numbers, which combine to form the IPv4 address hosting the server.
The researchers note the poem carries no links, no files to download, and no encrypted text that could easily be flagged as malicious, which is why the IP address hidden within it would not be obvious without access to the malware referencing it. Their write-up lists all the C2 IP addresses, plus when they were first and last seen.
Proof of concept for CVE-2026-10520
CVE-2026-10520 is described in NVD detail for CVE-2026-10520, published Jun 9, 2026, as: An OS Command Injection vulnerability in Ivanti Sentry before the R10.5.2, R10.6.2 and R10.7.1 versions allows a remote unauthenticated user to achieve root-level remote code execution.
A public proof-of-concept is maintained in CVE-2026-10520 PoC by 0xBlackash. That project reports two critical vulnerabilities affecting Ivanti Sentry:
- CVE-2026-10520 → CVSS 10.0 - Pre-auth OS Command Injection (RCE as root)
- CVE-2026-10523 → CVSS 9.9 - Authentication Bypass
The flaws allow unauthenticated attackers to achieve full system compromise, with Pre-Authentication and no credentials needed.
Installation from that repository uses:
git clone https://github.com/0xBlackash/CVE-2026-10520.git
cd CVE-2026-10520
chmod +x CVE-2026-10520.py
General invocation pattern is:
python3 CVE-2026-10520.py --url <TARGET> --cmd <COMMAND>
Documented examples:
# Basic usage
python3 CVE-2026-10520.py --url https://target.com:8443 --cmd "id"
# Verbose mode
python3 CVE-2026-10520.py --url https://target.com:8443 --cmd "whoami" -v
# With proxy
python3 CVE-2026-10520.py --url https://target.com:8443 --cmd "uname -a" --proxy 127.0.0.1:8080
# Check kernel
python3 CVE-2026-10520.py --url https://target.com:8443 --cmd "uname -a"
A successful run against a vulnerable target is reported as:
[+] Target is VULNERABLE!
Command Output:
uid=0(root) gid=0(root) groups=0(root)
Author credit for that PoC is Ashraf Zaryouh 0xBlackash, see author profile.
An additional summary is in CVE-2026-10520 guide, which describes CVE-2026-10520 as an actively exploited OS command injection on Ivanti Sentry, the mobile-device gateway that proxies email / calendar / SharePoint for every managed phone.
Detection and mitigation
Patch every Ivanti Sentry instance to a fixed release: R10.5.2, R10.6.2 and R10.7.1 or later, on emergency change. Review internet-facing deployments of LiteLLM, Ollama, Gotenberg and Gitea for exposure, and confirm services are patched and protected rather than left open after AI-assisted deployment.
Hunt for:
- outbound contact to
5.78.73[.]122and other C2 IP addresses with first- and last-seen times listed in the Black Lotus Labs write-up - presence of
dash.csscontainingOn the Nature of Connectionfrom the fork of the nodejs.org site byejejejdfbbebe - XMRig and Iron miner processes and connections to Kryptex mining infrastructure
- unexpected vulnerability scanning originating from AI workload hosts, indicating reuse as exploit servers
uid=0(root) gid=0(root) groups=0(root)command output during validation of Ivanti Sentry with the PoC above
Isolate affected AI servers, rotate credentials that traversed LiteLLM and related pipelines given the prior LiteLLM credential-theft history, and rebuild compromised hosts from known-good images.
Technical background
This section covers general concepts only, not specifics of this incident.
OS command injection occurs when an application passes attacker-controlled input to a system shell without adequate neutralization. A generic illustrative pattern, unrelated to the CVE above, looks like:
# GENERIC illustrative example only - not from this incident
ping -c 1 127.0.0.1; id
Dead-drop resolvers are a generic C2 resilience technique where malware fetches a benign-looking public resource and extracts an address using fixed offsets or delimiters. A generic illustrative approach, unrelated to PoeLLM's dictionary mapping, looks like:
# GENERIC illustrative example only - not from this incident
import re
text = fetch_public_page()
m = re.search(r"between START(.*?)END", text, re.I)
ipv4 = decode_generic(m.group(1)) # placeholder function
connect(ipv4)