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
POC-CopyEscape-CVE-2026-17106 — PoC funcional de CVE-2026-17106 (CopyEscape): carrera TOCTOU en docker cp que permite escritura arbitraria en el host Docker. Laboratorio Docker + monitor inotify + LD_PRELOAD. Variante macOS inocua y Linux destructiva. | Kitploit
Tools/GitHubGitHub/686f6c61/poc-copyescape-cve-2026-17106
Privilege EscalationContainer SecurityVulnerability AnalysisExploitationLearning & EducationContainer EscapeAdversarial AttackLabs & Practice

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share
GitHub
686f6c61/poc-copyescape-cve-2026-17106

POC-CopyEscape-CVE-2026-17106

PoC funcional de CVE-2026-17106 (CopyEscape): carrera TOCTOU en docker cp que permite escritura arbitraria en el host Docker. Laboratorio Docker + monitor inotify + LD_PRELOAD. Variante macOS inocua y Linux destructiva.

View Repository
1728 days agoNot yet reviewed

CopyEscape — PoC for CVE-2026-17106

Educational Proof of Concept of CopyEscape (CVE-2026-17106), a TOCTOU race condition vulnerability in docker cp that allows a malicious container to write arbitrary files on the Docker host. Inspired by the original work of masasron, who discovered and documented the vulnerability in the blog post "CopyEscape: Taking Over Docker Hosts with docker cp".


Table of contents

  1. Executive summary
  2. Legal notice
  3. Chain architecture
  4. Requirements
  5. Repository structure
  6. Quick usage guide
  7. Exploitation verification
  8. Comparison with the original
  9. Mitigation
  10. Credits
  11. License

Executive summary

CVE-2026-17106 is a race condition vulnerability (TOCTOU) in the tar file extraction that the Docker daemon produces during docker cp <contenedor>:<ruta> <destino>. It affects Docker CLI 29.6.1 and earlier versions; patched as of 29.7.0. The bug resides in the CLI (host-side tar extraction), not in the daemon.

The chain dubbed CopyEscape demonstrates how, starting solely from a running container with no extra capabilities, an attacker can:

  1. Camouflage a real directory /watched/file.txt/ as a regular file to any process that opens it inside the container, using an LD_PRELOAD library that intercepts open, openat, openat2, fopen, stat, lstat, fstatat, statx, and the 64 variants.
  2. Keep a 16 MiB decoy file aaa.txt that forces the daemon to take long enough to produce the tar for the monitor to win the race.
  3. Monitor daemon accesses with inotify and, during the race window, replace an escape/ subdirectory with an absolute symlink to the host target ( on macOS or on Linux) using two atomic calls with rollback.

The result is arbitrary file write on the host with the permissions of the process running docker cp. The Linux variant overwrites /usr/bin/runc and achieves root code execution on the host at the next docker run / exec.


Legal notice

This repository contains strictly educational and defensive material.

  • Purpose: demonstrate the exploitation chain for training, self-auditing, and validating patches.
  • Authorized use: run it only against systems you own or for which you have explicit written authorization.
  • Prohibited: any use against third-party systems without consent. The repository author is not responsible for misuse of the material included here.
  • Responsibility: the operator is solely responsible for compliance with applicable legislation (LOPD/GDPR in Spain, CFAA in the USA, etc.).
  • The Linux variant destroys the host's runc: use it only in a disposable VM with a verified backup.

The PoC ships with a harmless macOS variant (writes ~/pwnd as a marker) whose sole purpose is to serve as a reproducible demonstration.


Chain architecture

root@kitploit:~
┌─────────────────────────────────────────────────────────────────────┐
│  1. LD_PRELOAD camufla /watched/file.txt como archivo regular       │
│     open/openat/openat2/fopen/stat/lstat/fstatat/statx → decoy       │
│     docker exec ... cat /watched/file.txt  →  "top-level file"       │
└──────────────────────────────────────────┬──────────────────────────┘
                                           │
                                           ▼
┌─────────────────────────────────────────────────────────────────────┐
│  2. Layout real dentro del contenedor                               │
│     /watched/file.txt/                                               │
│     ├── aaa.txt            (16 MiB de 'B', cebo lento)               │
│     ├── escape/            (directorio real inicial)                 │
│     ├── escape/<basename>  (payload: runc o pwnd)                    │
│     └── .swap-escape       (symlink → /Users/<usr> o /usr/bin)       │
└──────────────────────────────────────────┬──────────────────────────┘
                                           │
                                           ▼
┌─────────────────────────────────────────────────────────────────────┐
│  3. docker cp pide tar al daemon                                    │
│     daemon recorre /watched/file.txt/ y abre aaa.txt                │
│     inotify detecta IN_OPEN sobre aaa.txt                           │
└──────────────────────────────────────────┬──────────────────────────┘
                                           │
                                           ▼
┌─────────────────────────────────────────────────────────────────────┐
│  4. Monitor pivot: dos rename(2) atomicos con rollback              │
│     escape/ → .old-escape/   (backup)                                │
│     .swap-escape → escape/   (symlink al target del host)            │
└──────────────────────────────────────────┬──────────────────────────┘
                                           │
                                           ▼
┌─────────────────────────────────────────────────────────────────────┐
│  5. Tar resultante contiene:                                        │
│     escape → /Users/<usr>   (symlink absoluto)                       │
│     escape/<basename>        (entrada hija que atraviesa el symlink) │
└──────────────────────────────────────────┬──────────────────────────┘
                                           │
                                           ▼
┌─────────────────────────────────────────────────────────────────────┐
│  6. CLI vulnerable extrae symlink + hija                            │
│     crea escape → /Users/<usr> en el destino local                   │
│     extrae escape/<basename> A TRAVES del symlink                    │
│     escribe /Users/<usr>/<basename> en el host                       │
└──────────────────────────────────────────┬──────────────────────────┘
                                           │
                                           ▼
┌─────────────────────────────────────────────────────────────────────┐
│  macOS: ~/pwnd con "COPYESCAPE_MACOS_DEMO"  (demo inocua)           │
│  Linux: /usr/bin/runc sobrescrito          (RCE como root)          │
└─────────────────────────────────────────────────────────────────────┘

Requirements

The PoC is built to run on macOS with:

  • Docker Desktop 4.81+ running (the daemon can be any version; the bug is in the CLI).
  • curl, tar, git, and docker in PATH.
  • Internet connection to download the vulnerable CLI 29.6.1 (about 18 MB) and the base image alpine:3.21.
  • HOME shaped like /Users/<usuario>.

No root is needed for the macOS variant. The Linux variant requires root and a disposable VM.

The run-poc.sh runner automatically downloads the vulnerable CLI 29.6.1 binary from Docker's official site (download.docker.com). It does not modify the system's Docker Desktop installation: it uses the current daemon but invokes the downloaded binary for the docker cp operation.


Repository structure

root@kitploit:~
POC CopyEscape (CVE-2026-17106)/
├── README.md                 ← Este archivo
├── LICENSE                   ← Licencia MIT
├── .gitignore
├── Dockerfile                ← Dockerfile unificado (macos | linux)
├── entrypoint.sh             ← Arranque del monitor sin LD_PRELOAD
├── monitor.c                 ← Monitor inotify unificado (una sola fuente)
├── watched_preload.c         ← LD_PRELOAD con cobertura ampliada
└── run-poc.sh                ← Runner robusto con reintentos

The cli-vulnerable/ directory (downloaded CLI 29.6.1) is excluded from the repository via .gitignore. The runner downloads it automatically if it is not present.


Quick usage guide

1. Run the PoC (macOS variant, harmless)

root@kitploit:~
cd poc-v2
./run-poc.sh

The runner:

  1. Downloads the vulnerable CLI 29.6.1 if it is not present.
  2. Builds the Docker image copyescape-macos-pocv2:local.
  3. Starts the prepared container with COPYESCAPE_HOST_HOME=$HOME.
  4. Waits until /watched/file.txt is readable inside the container.
  5. Runs docker cp with the vulnerable CLI.
  6. Verifies the creation of the ~/pwnd marker.

2. Runner options

root@kitploit:~
./run-poc.sh 10         # 10 intentos (la carrera es probabilistica)
./run-poc.sh --cleanup  # 5 intentos y borra la imagen al final

3. Expected output

root@kitploit:~
[run-poc] CLI vulnerable: 29.6.1
[run-poc] Intento 1/5 (contenedor copyescape-pocv2-NNNN-RRRR)
[run-poc]   /watched/file.txt lee: top-level file
[run-poc]   docker cp (CLI 29.6.1)...
[run-poc]   EXITO en intento 1: se creo /Users/<tu-usuario>/pwnd
  Contenido del marcador: COPYESCAPE_MACOS_DEMO
[run-poc]   Logs del monitor:
    [monitor] plataforma=macos target_dir=/Users/<tu-usuario> target_file=/Users/<tu-usuario>/pwnd quiet_ms=400 trigger=aaa.txt
    [monitor] pivoted /watched/file.txt/escape -> /Users/<tu-usuario>
[run-poc] Resumen: 1 exito en 1 intento(s).

4. Cleanup

root@kitploit:~
rm -f -- "$HOME/pwnd"
rm -rf -- poc-v2/file.txt
docker image rm copyescape-macos-pocv2:local

Exploitation verification

Once the chain is complete, the following elements serve as evidence:


Comparison with the original

What remains from the original

The idea and strategy are masasron's: the TOCTOU race against the tar producer, the LD_PRELOAD camouflage, the 16 MiB decoy, the two-rename(2) pivot, and the escape/ + .swap-escape structure. Without that design, this rewrite would not exist. The conceptual scheme is identical.

What has been rewritten

Approximately 15-20% are lines that match literally (short utilities and layout constants). The rest is new code.


Mitigation

  • Update the Docker CLI to 29.7.0 or higher. The PoC stops working (verified with 29.7.2).
  • Do not run docker cp from a container you do not trust, and never as root on Linux.
  • Simple detection: watch for absolute symlink creation inside the docker cp destination during extraction, or block in the daemon tars that contain child entries under a symlink.
  • The root of the bug is the same class of flaw as TarSlip / ZipSlip: the CLI does not validate that subsequent entries do not escape via an already created symlink.

Credits

  • Original research and disclosure: masasron — https://github.com/masasron/CopyEscape-CVE-2026-17106
  • PoC and packaging of this repository: own work for educational purposes, rewritten from scratch based on the original idea.

License

Distributed under the MIT license. See the LICENSE file for more details.

Download Tool
/Users/<usuario>
/usr/bin
rename(2)
  • The resulting tar contains the escape symlink followed by a child entry escape/<basename>; the vulnerable CLI creates the symlink on the client and extracts the child entry through it, writing outside the destination chosen by the user.
  • ResourceExpected evidence
    ~/pwndFile with content COPYESCAPE_MACOS_DEMO\n
    poc-v2/file.txt/Directory (not a file) with escape -> /Users/<tu-usuario> (symlink) and aaa.txt (16 MiB)
    docker logs <contenedor>Line pivoted /watched/file.txt/escape -> /Users/<tu-usuario>
    CLI 29.7.2 (docker cp with patched CLI)The marker is not created; the PoC fails
    FileOriginal linesNew linesChange
    watched_preload.c89257Rewritten: openat2, fstatat, statx, stat64, lstat64, open64, fopen64 wrappers; thread-safe constructor; guard against dlsym == NULL; O_TMPFILE
    monitor.c (macos + linux)259 + 233 = 492 (duplicated)344 (unified)Rewritten and unified with -DCOPYESCAPE_TARGET_*; rollback in try_pivot; configurable exit_quiet_ms and trigger; robust detection
    entrypoint.sh35env -u LD_PRELOAD instead of unset
    Dockerfile2243Unified; digest pin; --platform; no -Werror; -static; LABEL
    demo-macos.sh → run-poc.sh88166Rewritten: race retries; failure logs; --cleanup; validation delegated to the binary