Self-hosted job schedulers are an unusually good target for cryptomining botnets, and the pattern is old enough to be well documented. In 2020, two Apache Airflow flaws — CVE-2020-13927, an insecure default that left the Experimental REST API open to unauthenticated requests in versions before 1.10.11, and CVE-2020-11978, a command injection in a bundled example DAG — combined into a fully unauthenticated remote code execution chain, with a public proof of concept published by researcher Pierre Berba at github.com/pberba/CVE-2020-11978. Four years later, CVE-2024-39877 showed the pattern wasn't fixed for good: a CVSS 8.8 flaw in Airflow 2.4.0 through 2.9.2 let an authenticated DAG author execute arbitrary code via a crafted doc_md field, patched in 2.9.3. Meanwhile Rundeck disclosed CVE-2021-39132, a YAML deserialization bug in rundeck-core versions 3.3.0–3.3.13 and 3.4.0–3.4.2 that ran untrusted code from a crafted plugin or ACL policy file. Separately, botnets like LemonDuck have skipped the scheduler software entirely and gone straight for exposed Docker Engine APIs to plant their own cron jobs. This post breaks down why scheduler and orchestrator tooling keeps ending up as the entry point — and the persistence mechanism — for mining malware.
Why do auth-bypass bugs in schedulers turn into full RCE so often?
Auth-bypass bugs in schedulers turn into full RCE because the management API and the code-execution surface sit right next to each other by design — the whole point of a scheduler is to run arbitrary jobs on command. Airflow's Experimental REST API, left open to unauthenticated requests by default before version 1.10.11 (CVE-2020-13927), was never supposed to be reachable without credentials; once it was, an attacker could call it to trigger DAG runs. Airflow shipped example DAGs enabled by default, and one of them, example_trigger_target_dag, contained a command injection flaw (CVE-2020-11978) that any authenticated caller could exploit to run OS commands as the Airflow worker user. Neither bug alone is catastrophic — the API bug grants access, the DAG bug grants execution — but chained together they produce unauthenticated RCE with no exploit development required beyond stitching two documented requests together, which is exactly what Pierre Berba's public PoC and the later Metasploit module demonstrated.
How does YAML deserialization in Rundeck lead to code execution?
YAML deserialization leads to code execution in Rundeck because certain YAML loaders can be tricked into instantiating arbitrary Java objects instead of plain data structures, and if one of those objects has a constructor or setter with a side effect, that side effect runs during parsing — before any application logic inspects the value. Rundeck's GitHub security advisory for CVE-2021-39132 describes exactly this: an authorized user could upload a zip-format plugin containing a crafted plugin.yaml, or a crafted ACL policy YAML file via a project archive, and the server would execute untrusted code while deserializing it. The bug affected org.rundeck:rundeck-core versions 3.3.0–3.3.13 and 3.4.0–3.4.2, fixed in 3.3.14 and 3.4.3. It required some existing privilege — admin access to upload a plugin, or ACL-management rights to upload a policy file — which is why it's a privilege-escalation-to-RCE bug rather than a fully anonymous one, but in any environment where multiple teams share a Rundeck instance with tiered permissions, that's a realistic starting point.
Why do cryptomining botnets specifically target Docker and scheduler APIs?
Cryptomining botnets specifically target Docker and scheduler management APIs because those APIs are frequently exposed to the internet without authentication, and because compromising them hands the attacker a container runtime rather than a single shell. CSO Online and CrowdStrike have both documented the LemonDuck botnet's campaign against misconfigured, unauthenticated Docker Engine APIs: the malware launches a malicious container with a custom entrypoint that fetches a file named core.png — disguised as an image but actually a Bash script — which installs a Linux cron job. That cron job then pulls down a second disguised payload, a.asp, which downloads and runs the XMRig miner while attempting to disable cloud-provider monitoring agents. The Docker API itself isn't a scheduler, but the attack's entire second stage depends on planting a scheduled job, because a shell obtained through a container escape or a one-off API call disappears on restart — cron does not.
Why does the exploited primitive keep being an old, boring one?
The exploited primitive keeps being an old, boring one — an open API, a bad default, an unsafe deserializer — because novel cryptographic or logic flaws aren't necessary when a scheduler already has legitimate, privileged reasons to execute arbitrary code on a recurring basis. An attacker doesn't need to discover a new memory-corruption bug in XMRig's mining code; they need one foothold that runs code once, and a persistence primitive that reruns it forever. Container-focused threat groups like TeamTNT, which target exposed Docker and Kubernetes environments, follow the identical logic: once initial access is achieved through any vector, the attacker's next move is almost always to write a cron job or CronJob entry, not to escalate further. That's why Airflow's two 2020 CVEs, Rundeck's 2021 deserialization bug, and Docker API exposure all funnel toward the same outcome — XMRig or a similar Monero miner running under a scheduled task that survives a reboot — despite having nothing else in common as vulnerabilities.
How should teams defend self-hosted scheduler deployments?
Teams should defend self-hosted scheduler deployments by treating the management API's authentication posture as a release-blocking control, not a configuration afterthought, and by patching promptly since these bugs are publicly documented with working exploits. For Airflow, that means confirming auth_backend is set to deny unauthenticated requests, setting load_examples = False in production, and tracking the CVE feed for the project — CVE-2024-39877 proved the software is still an active target four years after the 2020 chain. For Rundeck, it means restricting who holds plugin-upload and ACL-management privileges, since CVE-2021-39132 required that access before deserialization could be triggered, and upgrading past 3.4.3 or 3.3.14. For any container or scheduler management API, it means never exposing the control plane to the internet without authentication — the single control that would have stopped LemonDuck's Docker campaign outright — and auditing cron/CronJob entries as a detection signal, since an unexpected scheduled job is often the clearest artifact a cryptomining compromise leaves behind.
How Safeguard helps
Safeguard's vulnerability management pipeline gives teams the CVE and dependency visibility this class of bug depends on: it tracks known CVEs like CVE-2020-11978, CVE-2020-13927, CVE-2024-39877, and CVE-2021-39132 against the actual versions of Airflow, Rundeck, and other self-hosted tooling declared in your manifests and SBOMs, so a team running an affected version gets flagged before an attacker finds the same open API. Because Safeguard ingests SBOMs across your software supply chain rather than scanning one repository at a time, it can answer "are any of our self-hosted schedulers on a vulnerable version" the moment a new CVE is disclosed, instead of requiring someone to remember to check every internal tool by hand.