Skip to content

VivekGubbala/docker-cop

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Docker Secret Scanner

A Node.js CLI tool that scans Docker images for hardcoded secrets, API keys, private keys, tokens, and sensitive files. It inspects the full image — layer filesystems, Dockerfile build history, and image config metadata — to catch secrets that other tools miss.

Features

  • 66 detection rules — AWS, GCP, Azure, Stripe, GitHub, GitLab, Slack, OpenAI, Anthropic, HuggingFace, and 50+ more
  • 3-layer deep scanning — scans layer filesystems, docker history (ENV/ARG/RUN instructions), and image config (environment variables & labels)
  • Streaming output — results render as each image completes, not after all finish
  • Parallel scanning — scan multiple images concurrently with configurable concurrency
  • Disk-safe for large batches--cleanup removes each image after scanning so you never run out of storage
  • Private registry support — authenticate with Docker Hub, GHCR, ECR, or any registry via token
  • Low false positives — 18 allow rules skip known-noisy paths (vendor dirs, runtime libs, docs, test fixtures) plus placeholder detection
  • Shannon entropy detection — catches high-entropy strings that don't match known patterns
  • Rich terminal output — colored severity tables, spinners with progress, and summary stats
  • Config file support — define scan targets in YAML or JSON
  • Secret redaction — output shows first 4 characters + **** to avoid leaking secrets in logs

Prerequisites

  • Node.js >= 18
  • Docker — daemon must be running

Installation

git clone <repo-url>
cd security-scanner
npm install
npm link   # makes 'scanner' available globally

Usage

Scan images by name

scanner scan nginx:latest myapp:v1 python:3.12-slim

Scan with options

scanner scan myapp:latest \
  --severity HIGH \
  --format table \
  --max-file-size 5 \
  --concurrency 4

Scan private images (Docker Hub)

# Via CLI flags
scanner scan mycompany/private-app:latest \
  --registry-user myuser \
  --registry-token dckr_pat_xxxxxxxxxxxxx

# Via environment variables
export DOCKER_USER=myuser
export DOCKER_TOKEN=dckr_pat_xxxxxxxxxxxxx
scanner scan mycompany/private-app:latest

# Via config file
scanner scan-config scan-config.yaml

Scan from a private registry (GHCR, ECR, etc.)

scanner scan ghcr.io/myorg/myapp:latest \
  --registry ghcr.io \
  --registry-user myuser \
  --registry-token ghp_xxxxxxxxxxxxx

Large-scale background scanning

When scanning many images (GBs/TBs), use --cleanup to remove each image from disk after scanning and redirect output to a file:

# Table output — stream results to a log file
nohup scanner scan img1:latest img2:latest img3:latest ... \
  --cleanup \
  --concurrency 2 \
  --severity MEDIUM \
  > scan-results.log 2>&1 &

# JSON output — one JSON object per image (JSONL format), ideal for pipelines
nohup scanner scan img1:latest img2:latest img3:latest ... \
  --cleanup \
  --format json \
  > scan-results.jsonl 2>&1 &

# Markdown output — clean tables that render in GitHub, Notion, wikis, etc.
nohup scanner scan img1:latest img2:latest img3:latest ... \
  --cleanup \
  --format markdown \
  > scan-report.md 2>&1 &

# Monitor progress
tail -f scan-results.log

With --cleanup enabled, only --concurrency images (default 3) exist on disk at any given time. The pipeline per image is:

pull → scan → output results → docker rmi → next image

You can also define all images in a config file:

# large-scan.yaml
images:
  - mycompany/service-a:latest
  - mycompany/service-b:latest
  - mycompany/service-c:latest
  # ... hundreds of images

cleanup: true
concurrency: 2
severity: MEDIUM
nohup scanner scan-config large-scan.yaml > results.log 2>&1 &

Scan from a config file

scanner scan-config scan-config.example.yaml

Options

Flag Description Default
-s, --severity <level> Minimum severity: LOW, MEDIUM, HIGH LOW
-f, --format <type> Output format: table, json, markdown table
--max-file-size <mb> Skip files larger than this (MB) 10
-c, --concurrency <n> Max parallel image scans 3
--cleanup Remove images from disk after scanning off
--registry <url> Registry server URL Docker Hub
--registry-user <user> Registry username env DOCKER_USER
--registry-token <token> Registry token/password env DOCKER_TOKEN

Exit Codes

Code Meaning
0 No secrets found
1 Secrets detected
2 Runtime error (Docker not available, invalid image, etc.)

Example Output

Results stream to the terminal as each image finishes scanning:

  Docker Secret Scanner v1.0.0

── myapp:latest ──────────────────────────────────────────────
┌──────────┬──────────────────────┬────────────────────────────┬──────┬──────────────────┐
│ Severity │ Rule                 │ File                       │ Line │ Match            │
├──────────┼──────────────────────┼────────────────────────────┼──────┼──────────────────┤
│ HIGH     │ AWS Access Key ID    │ /app/config.py             │ 12   │ AKIA****         │
│ HIGH     │ OpenAI Project Key   │ [Image Config] ENV         │ -    │ sk-p****         │
│          │                      │ OPENAI_API_KEY             │      │                  │
│ HIGH     │ Stripe Secret Key    │ [Dockerfile] Layer 3       │ -    │ sk_l****         │
│ MEDIUM   │ Database Connection  │ /app/.env                  │ 3    │ post****         │
│          │ String               │                            │      │                  │
│ MEDIUM   │ Hardcoded Password   │ [Dockerfile] Layer 5       │ -    │ MyS3****         │
└──────────┴──────────────────────┴────────────────────────────┴──────┴──────────────────┘

⠋ Scanning... (1/3 done)

── nginx:latest ──────────────────────────────────────────────
  No secrets found.

⠋ Scanning... (2/3 done)

── redis:latest ──────────────────────────────────────────────
  No secrets found.

────────────────────────────────────────────────────────────
  Scanned 3 images
  Summary: Found 5 secrets in 1 image (3 HIGH, 2 MEDIUM, 0 LOW)

With --format json, each image outputs one JSON object per line (JSONL), making it easy to process with jq:

# Find all HIGH severity findings
scanner scan myapp:latest --format json | jq '.findings[] | select(.severity == "HIGH")'

With --format markdown, output is clean markdown that renders in GitHub, Notion, or any wiki. Ideal for logging to a file:

scanner scan myapp:latest nginx:latest --format markdown > report.md

Produces a file like:

# Docker Secret Scanner v1.0.0

## myapp:latest

| Severity | Rule | File | Line | Match |
|----------|------|------|------|-------|
| **HIGH** | Stripe Secret Key | [Dockerfile] Layer 2 | - | `sk_l****` |
| **HIGH** | OpenAI Project Key | [Image Config] ENV OPENAI_API_KEY | - | `sk-p****` |
| *MEDIUM* | Hardcoded Password | /app/config.py | 5 | `MyS3****` |

## nginx:latest

No secrets found.

---

*Scanned 2 images*

**Summary:** Found **3** secrets in 1 image (**2** HIGH, **1** MEDIUM, **0** LOW)

What It Scans

Layer Filesystems

Extracts the image via docker save and streams through each layer tar, scanning every text file for secrets using regex pattern matching and entropy analysis.

Dockerfile Build History

Runs docker history --no-trunc to inspect the full build instructions. Catches secrets passed via ENV, ARG, or embedded in RUN commands — even if the files were deleted in later layers.

Image Config Metadata

Runs docker inspect to read environment variables and labels baked into the image config. Secrets set via ENV in a Dockerfile persist here permanently.

Detection Rules (66 rules)

HIGH Severity (37 rules)

Category Rules
Cloud Providers AWS Access Key, AWS Secret Key, GCP Service Account, Azure Storage Key, Alibaba Access Key
LLM Providers OpenAI API Key, OpenAI Project Key, Anthropic API Key, Google AI (Gemini) Key, Cohere API Key, HuggingFace Token, Replicate Token
Git Platforms GitHub PAT, GitHub OAuth, GitHub App Token, GitHub Refresh Token, GitHub Fine-Grained PAT, GitLab PAT
Payment / SaaS Stripe Secret Key, Shopify Token, SendGrid Key
Communication Slack Token
Package Registries NPM Access Token, PyPI Upload Token
CI/CD Heroku API Key, Pulumi API Token
Infrastructure Docker Config Auth, Atlassian API Token, Dropbox API Token
Crypto Private Key (PEM)
Generic Generic API Key Assignment
Sensitive Files SSH Private Key, .env File, PEM File, Docker Config, .npmrc, .pypirc

MEDIUM Severity (25 rules)

Database Connection String, Hardcoded Password, JWT Token, Bearer Token, Twilio Key, Mailchimp Key, Mailgun Key, Age Secret Key, Slack Webhook, Discord Token, HashiCorp Terraform Token, Databricks Token, Doppler Token, PlanetScale Password/Token, Grafana Token, New Relic Keys, Dynatrace Token, Linear Token, Postman Token, Mapbox Token, Fastly Token, RubyGems Token, Generic Secret Assignment

LOW Severity (4 rules)

Stripe Publishable Key, Facebook Token, Twitter/X Token, High-Entropy String (Shannon entropy > 4.5)

Allow Rules (False Positive Reduction)

Files in these paths are automatically skipped:

Rule Skipped Path
Python dist-info .dist-info/
Test files test/, __tests__/, spec/, fixtures/
Examples examples/
Vendor /vendor/
System dirs /usr/share/, /usr/include/, /usr/lib/
Locales /locale/, /locales/
Markdown *.md
Node runtime /opt/yarn-v*/
Go runtime /usr/local/go/
Python runtime /usr/local/lib/python*/
Ruby runtime /usr/lib/gems/
WordPress /usr/src/wordpress/
Anaconda logs /var/log/anaconda/
Docs docs/
Changelogs CHANGELOG, CHANGES, HISTORY
Licenses LICENSE, COPYING, NOTICE
Man pages /man/man*/
Go modules /go/pkg/mod/

Additionally, binary files (images, archives, compiled objects) and directories like node_modules, .git, and __pycache__ are always skipped.

Config File Format

# scan-config.yaml
images:
  - nginx:latest
  - myapp:v1
  - node:18-alpine

severity: LOW        # LOW | MEDIUM | HIGH
format: table        # table | json
maxFileSize: 10      # Max file size in MB
concurrency: 3       # Max parallel scans
cleanup: false       # Remove images after scanning

# Registry authentication (for private images)
# Can also use env vars: DOCKER_REGISTRY, DOCKER_USER, DOCKER_TOKEN
# registry: https://index.docker.io/v1/
# registryUser: myuser
# registryToken: dckr_pat_xxxxxxxxxxxxx

Both YAML and JSON config files are supported. CLI flags override config file values.

Project Structure

security-scanner/
├── package.json
├── bin/
│   └── cli.js              # CLI entry point (Commander.js)
├── src/
│   ├── scanner.js           # Parallel image scanning orchestration
│   ├── docker.js            # docker save/history/inspect, tar extraction
│   ├── detector.js          # Secret detection engine (regex + entropy)
│   ├── rules.js             # 66 detection rules
│   ├── output.js            # Colored table output (chalk, cli-table3, ora)
│   ├── config.js            # YAML/JSON config file parsing
│   └── utils.js             # Binary detection, allow rules, entropy, helpers
└── scan-config.example.yaml

How It Works

                         ┌─────────────────────┐
                         │   scanner scan img   │
                         └──────────┬──────────┘
                                    │
                         ┌──────────▼──────────┐
                         │  Registry Login      │ (if --registry-token)
                         └──────────┬──────────┘
                                    │
                    ┌───────────────┼───────────────┐
                    ▼               ▼               ▼
            ┌──────────────┐ ┌───────────┐ ┌──────────────┐
            │ docker       │ │ docker    │ │ docker save  │
            │ history      │ │ inspect   │ │ + tar extract│
            │ --no-trunc   │ │ .Config   │ │ per layer    │
            └──────┬───────┘ └─────┬─────┘ └──────┬───────┘
                   │               │               │
                   ▼               ▼               ▼
            ┌──────────────────────────────────────────┐
            │         Detection Engine (detector.js)    │
            │  66 regex rules + entropy + allow rules   │
            └──────────────────┬───────────────────────┘
                               │
                               ▼
                    ┌─────────────────────┐
                    │  Stream results to   │
                    │  terminal / file     │
                    └──────────┬──────────┘
                               │
                               ▼
                    ┌─────────────────────┐
                    │  docker rmi          │ (if --cleanup)
                    └──────────┬──────────┘
                               │
                               ▼
                         Next image...

License

MIT

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors