docker exec -it injects a stray NUL byte into the output stream
Description
docker exec -it injects a single stray NUL byte (0x00) into the attached output stream on essentially every invocation. The byte lands at a variable position — sometimes before any command output, sometimes after it (at session teardown) — which suggests it's tied to the exec session's connection open/close handling rather than to the command or its output itself.
This is reproducible with the most minimal possible command (echo), with a fully cleared environment (env -i), with both bash and sh, across multiple hosts, and container base images — so it does not appear to depend on the container's OS, shell, or any user configuration.
In interactive use, this stray byte is normally invisible (terminals silently discard NUL). But when the attached process is producing live, cursor-addressed terminal output (e.g. a test runner redrawing progress in place with ANSI cursor-positioning escape sequences, or printing multi-byte UTF-8 characters), the stray byte can land mid-escape-sequence or mid-character, corrupting the terminal's rendering for the remainder of the session (extra/incorrect line wrapping, misplaced cursor, garbled output) until the user runs reset.
Reproduce
script -qec "docker exec -it <container> env -i sh -c 'echo minimal_env_test'" /tmp/nul_test.typescript < /dev/null
cat -A /tmp/nul_test.typescript
Replace <container> with the name/ID of any running container.
Expected output (cat -A, so $ marks end-of-line and ^M is a literal CR):
minimal_env_test^M$
Actual output — a stray NUL (rendered by cat -A as ^@) appears, either before or after the real output:
^@minimal_env_test^M$
or
minimal_env_test^M$
^@$
### Expected behavior
No NUL bytes
### docker version
```bash
Environment matrix
All reproduced with the exact command above (only the shell/image varied):
┌───────────────────────────┬─────────────────────────────────┬───────┬──────────────────────────────────────┐
│ Host │ Container image │ Shell │ docker version │
├───────────────────────────┼─────────────────────────────────┼───────┼──────────────────────────────────────┤
│ WSL2 (Ubuntu) │ custom Ubuntu 22.04-based image │ bash │ Docker version 29.4.0, build 9d7ad9f │
├───────────────────────────┼─────────────────────────────────┼───────┼──────────────────────────────────────┤
│ Linux VM (CI build agent) │ same Ubuntu 22.04-based image │ bash │ Docker version 29.4.0, build 9d7ad9f │
├───────────────────────────┼─────────────────────────────────┼───────┼──────────────────────────────────────┤
│ WSL2 (Ubuntu) │ alpine │ bash │ Docker version 29.4.0, build 9d7ad9f │
├───────────────────────────┼─────────────────────────────────┼───────┼──────────────────────────────────────┤
│ Linux │ alpine │ sh │ Docker version 29.7.2, build a7dcaa6 │
└───────────────────────────┴─────────────────────────────────┴───────┴──────────────────────────────────────┘docker info
$ docker info
Client: Docker Engine - Community
Version: 29.4.0
Context: default
Debug Mode: false
Plugins:
buildx: Docker Buildx (Docker Inc.)
Version: v0.33.0
Path: /usr/libexec/docker/cli-plugins/docker-buildx
compose: Docker Compose (Docker Inc.)
Version: v5.1.3
Path: /usr/libexec/docker/cli-plugins/docker-compose
Server:
Containers: 1
Running: 1
Paused: 0
Stopped: 0
Images: 40
Server Version: 29.4.0
Storage Driver: overlay2
Backing Filesystem: extfs
Supports d_type: true
Using metacopy: false
Native Overlay Diff: true
userxattr: false
Logging Driver: json-file
Cgroup Driver: systemd
Cgroup Version: 2
Plugins:
Volume: local
Network: bridge host ipvlan macvlan null overlay
Log: awslogs fluentd gcplogs gelf journald json-file local splunk syslog
CDI spec directories:
/etc/cdi
/var/run/cdi
Swarm: inactive
Runtimes: io.containerd.runc.v2 runc
Default Runtime: runc
Init Binary: docker-init
containerd version: 77c84241c7cbdd9b4eca2591793e3d4f4317c590
runc version: v1.3.5-0-g488fc13e
init version: de40ad0
Security Options:
apparmor
seccomp
Profile: builtin
cgroupns
Kernel Version: 6.8.0-137-generic
Operating System: Ubuntu 24.04.4 LTS
OSType: linux
Architecture: x86_64
CPUs: 16
Total Memory: 49.01GiB
Name: bamboo2
ID: 0dcff42d-59e0-4095-9f44-b62363d3ffff
Docker Root Dir: /var/lib/docker
Debug Mode: false
Username: cgsdev
Experimental: false
Insecure Registries:
::1/128
127.0.0.0/8
Live Restore Enabled: false
Firewall Backend: iptablesAdditional Info
- Using env -i rules out any shell startup file (.bashrc, /etc/profile, BASH_ENV, etc.) as the source.
- The variability in byte position (leading vs. trailing) across otherwise-identical runs suggests a race in stream setup/teardown rather than a deterministic content issue.
- Happens identically across two different host types (WSL2 and a plain Linux VM) and two different container base images (a custom Ubuntu 22.04 image and stock alpine), so it does not appear to be host- or image-specific.
Source: moby/moby