← posts / infrastructure

CopyEscape (CVE-2026-17106): patch docker cp, and stop copying out of running containers

A race in docker cp lets a malicious container write files anywhere the copying process can write on the host. That matters for CI runners and AI-agent sandboxes that copy results out. Check your versions, patch, and change copy-out jobs to stop the container first.

if.codesOct 5, 2026 · 5 min read#docker#security#cve#ciAI-assisted

docker cp is the command everyone uses to get build artefacts, test reports or an agent's output out of a container. CopyEscape, tracked as CVE-2026-17106, turns it around: if the container you copy from is malicious, it can make the copy write files outside the destination folder on your host. With sudo docker cp on Linux, Imperva, which found the bug, says that can go as far as root code execution.

If you only copy out of containers you built from images you trust, this is a patch-when-convenient bug. If you run CI for pull requests from strangers, or let a coding agent run arbitrary code in a container and then copy its results out, it is a patch-today bug. This post is the short version: what is affected, how to check, and how to change copy-out jobs so the next bug of this kind does not hit you either.

What goes wrong

When you run docker cp container:/path ./dest, the daemon walks the container's filesystem and builds a tar archive, which is then unpacked on the host. Imperva's write-up describes a race: while the walk is in progress, a process inside the running container swaps a directory for a symlink pointing outside the destination. The walker has already classified the path as a directory, then meets the symlink, and the result is an inconsistent archive that, when extracted, writes through the symlink. The extraction side, in the moby/go-archive library, did not restrict paths tightly enough to catch it.

A conceptual representation of a path redirection vulnerability.
A conceptual representation of a path redirection vulnerability.

Two conditions matter for your defences:

  • The container has to be running. The race needs a live process to do the swap. Imperva notes that stopped containers block the exploit.
  • The damage is bounded by who runs the copy. Files are written with the permissions of the process doing the extraction. A copy run as root can overwrite anything.

Affected and fixed versions

Per Imperva's advisory and Docker's announcements:

Updating software versions helps secure the container boundary.
Updating software versions helps secure the container boundary.
  • Docker Engine and CLI: fixed in 29.7.2. Earlier versions are affected.
  • Docker Desktop: fixed in 4.86.0, released on 10 August 2026.
  • Docker Sandboxes (the sbx cp command): fixed in 0.38.0.
  • Wiz's vulnerability database also lists moby/go-archive before 0.3.0 and Docker Compose before 5.4.0 as affected. It rates the bug CVSS v4.0 7.1 (High) and gives 18 August 2026 as the publication date.

Check your machines (2 minutes)

Engine and CLI versions come from docker version:

docker version --format 'client={{.Client.Version}} server={{.Server.Version}}'
docker compose version --short

On a Mac, the Docker Desktop version is in the app bundle (or under Settings → About):

defaults read /Applications/Docker.app/Contents/Info.plist CFBundleShortVersionString

For a fleet of CI runners, a small script that fails when the client or server is older than the fix is easier to drop into a health check:

#!/usr/bin/env bash
# copyescape-check.sh: exit 1 if Docker client or server is older than 29.7.2
set -euo pipefail
min=29.7.2

# true when $1 >= $2 (version sort)
at_least() { [ "$(printf '%s\n%s\n' "$1" "$2" | sort -V | head -n1)" = "$2" ]; }

status=0
for part in Client Server; do
  v=$(docker version --format "{{.${part}.Version}}" 2>/dev/null || echo unknown)
  if [ "$v" = unknown ]; then
    echo "$part: unknown (daemon unreachable?)"; status=1
  elif at_least "$v" "$min"; then
    echo "$part: $v ok"
  else
    echo "$part: $v VULNERABLE (need >= $min)"; status=1
  fi
done
exit $status
chmod +x copyescape-check.sh
./copyescape-check.sh

Then upgrade the usual way for each host: Docker Desktop's built-in updater, your package manager for docker-ce and docker-ce-cli on Linux, and a new runner image for hosted CI. Remember the CLI: on Linux it is a separate package from the Engine and can lag behind it.

Need the backend underneath done properly?I build and harden Go and Python backends. The estimate is free.

Change how you copy out, not just the version

Patching closes this bug. The pattern that made it exploitable, copying out of a live container you do not trust while running as root, will be the precondition for the next one. Three changes remove it.

1. Stop the container before you copy

The simplest pattern in CI is to create the container, run it to completion, and copy from the stopped container. docker start -a attaches and returns only when the container exits:

#!/usr/bin/env bash
set -euo pipefail
cid=$(docker create my-build-image:latest make test)
trap 'docker rm -f "$cid" >/dev/null' EXIT

docker start -a "$cid"          # runs the job; returns when it exits
docker cp "$cid":/work/out ./out # container is stopped: no live process to race

If the job leaves background processes running, docker start -a still returns once the main process exits, and Docker stops the container with it. For long-lived containers, run docker stop first and copy afterwards.

2. Drop sudo from copy automation

Run copy jobs as an unprivileged user that can only write to the artefact directory. On Linux that usually means a dedicated CI user in the docker group rather than sudo docker cp. Note that the docker group is itself root-equivalent for anyone who can run arbitrary docker run commands, so this limits the damage a bad copy can do, not the damage a bad user can do. Rootless Docker goes further, if your runners can use it.

3. Copy suspicious containers somewhere disposable

If you are pulling files out of a container you think is compromised, during an incident or when inspecting an agent that misbehaved, do it on a throwaway VM or runner, not your laptop or a long-lived build host. Imperva recommends exactly this, and it is cheap insurance for any future bug in the same code path.

For AI-agent sandboxes specifically

Agent sandboxes are the textbook case: the container runs code you did not write, chosen by a model, and the harness copies results out afterwards, often while the container is still up for the next step. If your harness uses docker cp or sbx cp:

AI sandboxes require strict controls when extracting generated files.
AI sandboxes require strict controls when extracting generated files.
  • upgrade Engine/CLI to 29.7.2+ and Sandboxes to 0.38.0+;
  • copy out only at the end of a run, after the container is stopped, or have the agent write results to a dedicated, empty output volume that the harness reads as an unprivileged user;
  • never run the harness as root just because it is convenient.

Sources

if.codesI build RAG, AI integrations and agent pipelines on Go and Python backends — and write about it here.
// keep reading

More posts on AI and backends.

// free quote

Read something you need? I’ll quote it for free.

RAG, AI integrations, agents or the backend underneath — tell me what you have and what should change. I read every request myself.

Free · no commitment

Tell me what you have. I’ll tell you what it takes.

1Describe the projectA few sentences is enough — about two minutes.
2I review itI read it myself and may ask a follow-up question.
3You get a free quoteScope, approach and estimate — yours to keep, no strings.
What kind of project is it?
Free and without obligation. Your details are used only to reply — see the privacy policy.