
The Most Comprehensive Docker Security Scanner
By Daniel Garcia (cr0hn) | GitHub | Website
Features • Installation • Quick Start • Documentation • Use Cases • What's New • Contributing
DockerScan v2.0 is a next-generation security scanner for Docker containers and images, completely rewritten in Go. It combines multiple security scanning techniques based on the latest 2024-2025 research, industry standards (CIS Benchmark, NIST SP 800-190), and real-world attack patterns discovered in production environments.
Complete compliance checking with 80+ automated controls:
Based on real 2024 attack campaigns:
40+ secret patterns including modern APIs (2024 update):
Critical 2024-2025 CVE detection:
Container runtime hardening checks:
DockerScan v2.0 is a complete rewrite from the ground up. Here's what changed from v1.x:
--from-file flag - Install CVE database from local file (offline/air-gapped)-q) - Suppress banner for CI/CD pipelinesPre-compiled binaries are automatically built and released via GitHub Actions for every version tag.
Supported Platforms:
curl -L https://github.com/cr0hn/dockerscan/releases/latest/download/dockerscan-linux-amd64 -o dockerscan
chmod +x dockerscan
sudo mv dockerscan /usr/local/bin/
curl -L https://github.com/cr0hn/dockerscan/releases/latest/download/dockerscan-linux-arm64 -o dockerscan
chmod +x dockerscan
sudo mv dockerscan /usr/local/bin/
curl -L https://github.com/cr0hn/dockerscan/releases/latest/download/dockerscan-darwin-amd64 -o dockerscan
chmod +x dockerscan
sudo mv dockerscan /usr/local/bin/
curl -L https://github.com/cr0hn/dockerscan/releases/latest/download/dockerscan-darwin-arm64 -o dockerscan
chmod +x dockerscan
sudo mv dockerscan /usr/local/bin/
Invoke-WebRequest -Uri "https://github.com/cr0hn/dockerscan/releases/latest/download/dockerscan-windows-amd64.exe" -OutFile "dockerscan.exe"
# Download checksums
curl -L https://github.com/cr0hn/dockerscan/releases/latest/download/checksums.txt -o checksums.txt
# Verify (Linux/macOS)
sha256sum -c checksums.txt --ignore-missing
# Clone repository
git clone https://github.com/cr0hn/dockerscan
cd dockerscan/dockerscan-v2
# Build
make build
# Install
sudo make install
# Or build manually
go build -o bin/dockerscan ./cmd/dockerscan
go install github.com/cr0hn/dockerscan/v2/cmd/dockerscan@latest
Before scanning, download the CVE database (updated daily, ~30MB compressed):
# Download latest CVE database from GitHub
dockerscan update-db
Tip: The database is updated daily via GitHub Actions. Run
update-dbperiodically to get the latest CVE data.
# Scan a Docker image
dockerscan nginx:latest
# Scan with specific scanners
dockerscan --scanners cis,secrets ubuntu:22.04
# Scan and save reports
dockerscan alpine:latest --output /tmp/reports
# Quiet mode (suppress banner)
dockerscan -q nginx:latest
╔══════════════════════════════════════════════════════════════════════════╗
║ ██████╗ ██████╗ ██████╗██╗ ██╗███████╗██████╗ ███████╗ ██████╗ █████╗ ███╗ ██╗
║ ██╔══██╗██╔═══██╗██╔════╝██║ ██╔╝██╔════╝██╔══██╗██╔════╝██╔════╝██╔══██╗████╗ ██║
║ ██║ ██║██║ ██║██║ █████╔╝ █████╗ ██████╔╝███████╗██║ ███████║██╔██╗ ██║
║ ██║ ██║██║ ██║██║ ██╔═██╗ ██╔══╝ ██╔══██╗╚════██║██║ ██╔══██║██║╚██╗██║
║ ██████╔╝╚██████╔╝╚██████╗██║ ██╗███████╗██║ ██║███████║╚██████╗██║ ██║██║ ╚████║
║ ║
║ Advanced Docker Security Scanner v2.0.0 ║
║ ║
║ Author: Daniel Garcia (cr0hn) ║
║ Website: https://cr0hn.com ║
╚══════════════════════════════════════════════════════════════════════════════════════╝
🔍 Scanning image: nginx:latest
═══════════════════════════════════════════════════════════════════
SCAN RESULTS
═══════════════════════════════════════════════════════════════════
📊 Summary:
Total Findings: 47
Duration: 2.3s
🔴 By Severity:
Critical: 8
High: 15
Medium: 18
Low: 6
📁 By Category:
CIS-Benchmark: 12
Secrets: 8
Supply-Chain: 5
Vulnerability: 10
Runtime-Security: 12
📄 JSON report saved to: dockerscan-report.json
📄 SARIF report saved to: dockerscan-report.sarif
dockerscan [COMMAND] [OPTIONS] <IMAGE>
Commands:
scan Scan a Docker image (default)
update-db Download or update the CVE database
Options: --from-file <path> Install from local SQLite file
version Show version information
help Show help message
Options:
-h, --help Show help message
-v, --version Show version
-q, --quiet Suppress banner output (quiet mode)
--scanners SCANNERS Comma-separated list of scanners to run
(default: all)
Options: cis,secrets,supplychain,vulnerabilities,runtime
--output DIR Output directory for reports (default: .)
--only-critical Show only critical/high severity findings
--verbose, -v Show scan progress (scanner names, findings count, image pull status). Output to stderr.
--debug Show verbose output plus internal errors and technical details. Output to stderr.
Authentication (for private registries):
--registry-user <username> Registry username
--registry-password <password> Registry password (not recommended, use env vars)
--registry <url> Registry URL (optional, auto-detected from image)
--docker-config <path> Path to Docker config file (default: ~/.docker/config.json)
Environment variables (recommended for CI/CD):
DOCKER_USERNAME or REGISTRY_USERNAME Registry username
DOCKER_PASSWORD or REGISTRY_PASSWORD Registry password or token
DOCKER_REGISTRY or REGISTRY Registry URL (optional)
Exit Codes:
0 No issues found
1 HIGH severity issues found
2 CRITICAL severity found
# Scan with all scanners (default)
dockerscan myapp:latest
# Only run specific scanners
dockerscan --scanners secrets,supplychain redis:7
# Save reports to specific directory
dockerscan --output /var/reports postgres:14
# Only show critical issues
dockerscan --only-critical production-app:v1.0
# Ver progreso del scan (scanner names, findings count, image pull status)
dockerscan --verbose ubuntu:22.04
# Debug detallado (errores internos, detalles técnicos)
dockerscan --debug ubuntu:22.04
# Scan private registry images (see Authentication section below)
dockerscan ghcr.io/myorg/private-app:v1.0
DockerScan supports three methods for authenticating with private registries:
The most convenient method - uses your existing Docker credentials:
# First, authenticate with your registry using Docker
docker login ghcr.io
# Username: your-username
# Password: ghp_your-token-here
# Now DockerScan can use these credentials automatically
dockerscan ghcr.io/myorg/private-app:latest
DockerScan automatically reads credentials from ~/.docker/config.json. This works with all registries you've logged into with docker login.
Credential helpers are fully supported. DockerScan natively resolves credentials through:
credsStore — global credential helper (e.g. osxkeychain on macOS with Docker Desktop, wincred on Windows, pass on Linux)credHelpers — per-registry credential helpers (takes precedence over credsStore)auths block in config.jsonOn macOS with Docker Desktop, this works out of the box with no extra configuration:
{
"credsStore": "osxkeychain"
}
DockerScan will call docker-credential-osxkeychain transparently to retrieve tokens, so you never need to pass credentials explicitly.
Best for automated environments and CI/CD pipelines:
# Set environment variables
export DOCKER_USERNAME=myusername
export DOCKER_PASSWORD=mytoken
# Scan private image
dockerscan ghcr.io/myorg/private-app:latest
# Or use alternative variable names
export REGISTRY_USERNAME=myusername
export REGISTRY_PASSWORD=mytoken
dockerscan myregistry.example.com/app:v1.0
CI/CD Example (GitHub Actions):
- name: Scan private image
env:
DOCKER_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
DOCKER_PASSWORD: ${{ secrets.REGISTRY_TOKEN }}
run: dockerscan ghcr.io/${{ github.repository }}:${{ github.sha }}
For quick testing only (credentials visible in process list):
dockerscan --registry-user myuser --registry-password mytoken ghcr.io/myorg/app:v1
Security Warning: This method exposes credentials in your shell history and process list. Use environment variables or Docker config instead.
# Using Docker config
docker login docker.io
dockerscan myusername/private-repo:latest
# Using environment variables
export DOCKER_USERNAME=myusername
export DOCKER_PASSWORD=dckr_pat_XXXXXXXXXXXXX
dockerscan myusername/private-repo:latest
# Using Docker config
echo $GITHUB_TOKEN | docker login ghcr.io -u USERNAME --password-stdin
dockerscan ghcr.io/myorg/myapp:v1.0
# Using environment variables
export DOCKER_USERNAME=myusername
export DOCKER_PASSWORD=ghp_XXXXXXXXXXXXXXXXXXXX
dockerscan ghcr.io/myorg/myapp:v1.0
# Get login credentials from AWS
aws ecr get-login-password --region us-east-1 | \
docker login --username AWS --password-stdin \
123456789012.dkr.ecr.us-east-1.amazonaws.com
# Scan ECR image
dockerscan 123456789012.dkr.ecr.us-east-1.amazonaws.com/myapp:latest
# Or use environment variables with ECR credentials
export DOCKER_USERNAME=AWS
export DOCKER_PASSWORD=$(aws ecr get-login-password --region us-east-1)
dockerscan 123456789012.dkr.ecr.us-east-1.amazonaws.com/myapp:latest
# Authenticate with gcloud
gcloud auth configure-docker gcr.io
# Scan GCR image
dockerscan gcr.io/my-project/myapp:latest
# For Artifact Registry
gcloud auth configure-docker us-docker.pkg.dev
dockerscan us-docker.pkg.dev/my-project/my-repo/myapp:latest
# Or use service account JSON key
export DOCKER_USERNAME=_json_key
export DOCKER_PASSWORD="$(cat service-account-key.json)"
dockerscan gcr.io/my-project/myapp:latest
# Login with Azure CLI
az acr login --name myregistry
# Scan ACR image
dockerscan myregistry.azurecr.io/myapp:v1.0
# Or use service principal credentials
export DOCKER_USERNAME=<service-principal-id>
export DOCKER_PASSWORD=<service-principal-password>
dockerscan myregistry.azurecr.io/myapp:v1.0
# Using Docker config
docker login registry.gitlab.com
dockerscan registry.gitlab.com/mygroup/myproject/myapp:latest
# Using environment variables with deploy token
export DOCKER_USERNAME=gitlab+deploy-token-1
export DOCKER_PASSWORD=DEPLOY_TOKEN_HERE
dockerscan registry.gitlab.com/mygroup/myproject/myapp:latest
# Standard authentication
docker login myregistry.example.com:5000
dockerscan myregistry.example.com:5000/myapp:latest
# With environment variables
export DOCKER_USERNAME=admin
export DOCKER_PASSWORD=secret
dockerscan myregistry.example.com:5000/myapp:latest
# Insecure registries (not recommended for production)
# Add to Docker daemon config: /etc/docker/daemon.json
# {
# "insecure-registries": ["myregistry.example.com:5000"]
# }
1. "authentication required" error
# Make sure you're logged in
docker login <registry>
# Or set environment variables
export DOCKER_USERNAME=your-username
export DOCKER_PASSWORD=your-token
2. "unauthorized: authentication failed" error
3. AWS ECR "authorization token has expired"
# ECR tokens expire after 12 hours - refresh them
aws ecr get-login-password --region us-east-1 | \
docker login --username AWS --password-stdin \
123456789012.dkr.ecr.us-east-1.amazonaws.com
4. Rate limiting on Docker Hub
5. Certificate errors with self-signed certificates
Automated compliance checking against CIS Docker Benchmark v1.7.0:
dockerscan --scanners cis nginx:latest
Checks include:
:latest)Detect real-world supply chain attacks:
dockerscan --scanners supplychain suspicious-image:1.0
Detects:
Find hardcoded secrets:
dockerscan --scanners secrets webapp:prod
Finds:
Detect known CVEs:
dockerscan --scanners vulnerabilities node:16
Checks for:
Audit runtime configurations:
dockerscan --scanners runtime running-container
Analyzes:
{
"target": {
"image_name": "nginx:latest"
},
"start_time": "2024-11-22T10:30:00Z",
"findings": [
{
"id": "CIS-4.1",
"title": "Container should not run as root",
"severity": "HIGH",
"category": "CIS-Benchmark",
"description": "Running containers as root increases attack surface...",
"remediation": "Use USER instruction in Dockerfile..."
}
],
"summary": {
"total_findings": 47,
"by_severity": {
"CRITICAL": 8,
"HIGH": 15
}
}
}
Compatible with GitHub Security, Azure DevOps, VS Code:
{
"$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
"version": "2.1.0",
"runs": [
{
"tool": {
"driver": {
"name": "DockerScan",
"version": "2.0.0"
}
},
"results": [...]
}
]
}
GitHub Actions:
name: Docker Security Scan
on: [push]
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build Docker image
run: docker build -t myapp:${{ github.sha }} .
- name: Install DockerScan
run: |
curl -L https://github.com/cr0hn/dockerscan/releases/latest/download/dockerscan-linux-amd64 -o dockerscan
chmod +x dockerscan
- name: Update CVE Database
run: ./dockerscan update-db
- name: Run Security Scan
run: ./dockerscan -q myapp:${{ github.sha }}
- name: Upload SARIF results
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: dockerscan-report.sarif
GitLab CI:
docker-security-scan:
stage: test
script:
- docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
- wget https://github.com/cr0hn/dockerscan/releases/latest/download/dockerscan-linux-amd64 -O dockerscan
- chmod +x dockerscan
- ./dockerscan update-db
- ./dockerscan -q $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
artifacts:
reports:
sast: dockerscan-report.sarif
# Comprehensive audit of production images
for image in $(docker images --format "{{.Repository}}:{{.Tag}}"); do
echo "Scanning $image..."
dockerscan $image --output /audit-reports/
done
# Generate summary report
cat /audit-reports/*.json | jq -s '
{
total_images: length,
total_findings: map(.summary.total_findings) | add,
critical_findings: map(.summary.by_severity.CRITICAL // 0) | add
}
'
# Fail deployment if critical issues found
dockerscan production-app:v2.0
exit_code=$?
if [ $exit_code -eq 2 ]; then
echo "❌ Critical vulnerabilities found. Deployment blocked."
exit 1
elif [ $exit_code -eq 1 ]; then
echo "⚠️ High severity issues found. Manual review required."
# Send notification...
else
echo "✅ No critical issues. Proceeding with deployment."
fi
# Generate CIS compliance report
dockerscan --scanners cis --only-critical all-production-images:* > cis-compliance-report.txt
# Weekly security scan for compliance
0 0 * * 0 /usr/local/bin/dockerscan --scanners cis,vulnerabilities production-images:latest --output /compliance/weekly/
# Pre-commit hook
#!/bin/bash
# .git/hooks/pre-commit
docker build -t local-test:latest .
dockerscan --only-critical local-test:latest
if [ $? -ne 0 ]; then
echo "❌ Docker security scan failed. Fix issues before committing."
exit 1
fi
dockerscan/
├── logo.png # Project logo
├── cmd/
│ ├── dockerscan/ # Main CLI application
│ │ └── main.go
│ └── nvd2sqlite/ # CVE database builder tool
│ └── main.go
├── data/ # CVE database (auto-updated daily)
│ ├── latest.db.gz # Compressed SQLite database
│ └── metadata.json # Database version info
├── internal/
│ ├── scanner/ # Extensible scanner framework
│ │ ├── scanner.go # Scanner interface & registry
│ │ ├── cis/ # CIS Benchmark implementation
│ │ ├── secrets/ # Secrets detection
│ │ ├── supplychain/ # Supply chain attacks
│ │ ├── vulnerabilities/ # CVE scanning
│ │ └── runtime/ # Runtime security
│ ├── report/ # Report generators
│ │ ├── json.go # JSON reporter
│ │ └── sarif.go # SARIF reporter
│ ├── models/ # Data models
│ │ └── models.go # Findings, scan results, etc.
│ └── config/ # Configuration
│ └── config.go # App config & banner
└── pkg/docker/ # Docker client wrapper
└── client.go
DockerScan uses a local SQLite database for CVE lookups. The database is automatically updated daily via GitHub Actions and hosted in the repository, so you always have access to the latest CVE data.
update-db command# Download latest database from GitHub (recommended)
dockerscan update-db
# Install from local file (for air-gapped/offline environments)
dockerscan update-db --from-file /path/to/cve-db.sqlite
Note: The first time you run
dockerscan, it will prompt you to download the database. After that, you can update it periodically withupdate-db.
For advanced users, you can build the CVE database from NVD directly:
# Build the tool
make build # Builds both dockerscan and nvd2sqlite
# Download CVEs (last 2.5 years by default)
./bin/nvd2sqlite --output data/cve-db.sqlite --verbose
# With NVD API key (10x faster - 50 req/30sec vs 5 req/30sec)
NVD_API_KEY=your-key ./bin/nvd2sqlite --output data/cve-db.sqlite --verbose
# Custom date range
./bin/nvd2sqlite --output data/cve-db.sqlite \
--start-date 2023-01-01 \
--end-date 2024-12-31
nvd2sqlite features:
Adding a new scanner is simple:
package myscan
import (
"context"
"github.com/cr0hn/dockerscan/v2/internal/models"
"github.com/cr0hn/dockerscan/v2/internal/scanner"
)
type MyScanner struct {
scanner.BaseScanner
}
func NewMyScanner() *MyScanner {
return &MyScanner{
BaseScanner: scanner.NewBaseScanner(
"my-scanner",
"Description of my scanner",
true, // enabled
),
}
}
func (s *MyScanner) Scan(ctx context.Context, target models.ScanTarget) ([]models.Finding, error) {
var findings []models.Finding
// Your scanning logic here...
return findings, nil
}
// Register in main.go:
// registry.Register(myscan.NewMyScanner())
Contributions are welcome! DockerScan is designed to be extensible.
git checkout -b feature/amazing-scanner)internal/scanner/git commit -am 'Add amazing scanner')git push origin feature/amazing-scanner)# Clone and setup
git clone https://github.com/cr0hn/dockerscan
cd dockerscan/dockerscan-v2
# Install dependencies
make deps
# Run tests
make test
# Run with coverage
make coverage
# Build
make build
# Format code
make fmt
# Lint
make lint
We especially welcome:
This project is licensed under the DockerScan Proprietary Source-Available License.
✅ You CAN (Free of Charge):
❌ You CANNOT (without express written permission or commercial license):
This license protects the project's sustainability by:
This is NOT open source - it's source-available with restrictions on commercial competitive use.
Required for:
Contact for commercial licensing:
📧 Email: cr0hn [at] cr0hn.com 🌐 Website: https://cr0hn.com 💼 Flexible licensing terms available for enterprise and startups
See the LICENSE file for complete legal terms.
Special thanks to:
⭐ If you find DockerScan useful, please star the repository! ⭐
Making Docker Security Accessible to Everyone
| Feature | v1.x (Python) | v2.0 (Go) |
|---|
| Language | Python 3.5+ | Go 1.21+ |
| Performance | ~500 images/hour | ~5000 images/hour |
| Memory Usage | 200-500 MB | 50-100 MB |
| Distribution | pip install + deps | Single binary |
| Security Scanners | 2 modules | 5 modules |
| CIS Benchmark | Partial | Full v1.7.0 (80+ checks) |
| Supply Chain | ❌ Not available | ✅ Based on 2024 research |
| Secret Patterns | 10 patterns | 40+ patterns |
| CVE Detection | Basic | 2024-2025 CVEs |
| Runtime Security | ❌ Not available | ✅ Full capabilities audit |
| SARIF Output | ❌ Not available | ✅ Full support |
| CI/CD Integration | Manual | Native (exit codes, SARIF) |
| Feature | DockerScan v2.0 | Trivy | Clair | Snyk | Grype |
|---|
| CIS Benchmark v1.7 | ✅ Full (80+ checks) | ❌ | ❌ | Partial | ❌ |
| Supply Chain Detection (2024) | ✅ Yes | ❌ | ❌ | ❌ | ❌ |
| Secrets Scanning | ✅ 40+ patterns | Basic | ❌ | ✅ | ❌ |
| CVE Database | ✅ 2024-2025 CVEs | ✅ | ✅ | ✅ | ✅ |
| Runtime Security | ✅ Full | ❌ | ❌ | ❌ | ❌ |
| SARIF Output | ✅ | ✅ | ❌ | ✅ | ✅ |
| Speed (Go) | ⚡ Very Fast | ⚡ Very Fast | 🐌 Slow | ⚡ Fast | ⚡ Very Fast |
| Extensible | ✅ Plugin system | Limited | Limited | ❌ | Limited |
| Exit Codes | ✅ CI/CD ready | ✅ | Partial | ✅ | ✅ |
| Cost | 🆓 Free | 🆓 Free | 🆓 Free | 💰 Paid tiers | 🆓 Free |
| Offline Mode | ✅ | ✅ | ❌ | ❌ | ✅ |
| License | Proprietary Source-Available | Apache-2.0 | Apache-2.0 | Proprietary | Apache-2.0 |