Most developers don't write Dockerfiles from scratch.
They copy snippets from blog posts, GitHub repositories, Stack Overflow answers, or previous projects.
The problem is that many of those examples aren't production-safe.
Over the years I've repeatedly seen Dockerfiles that:
Run containers as root
Store secrets directly in ENV instructions
Use latest image tags
Pipe curl output directly into bash
Expose unnecessary ports
Skip resource limits entirely
These issues often remain unnoticed until a security review, a penetration test, or a production incident.
I wanted a simple way to catch these problems early.
That led me to build dockersec.
An open-source CLI tool that scans Dockerfiles and docker-compose files for security vulnerabilities, misconfigurations, and bad practices.
The entire scanner runs offline and ships as a single Go binary.
The Problem: Bad Dockerfiles Reach Production
Let's take a simple example.
FROM node:latest
ENV AWS_SECRET_KEY=my-secret-key
RUN curl https://example.com/install.sh | bash
CMD ["npm", "start"]
At first glance this may look harmless.
But it contains multiple security problems:
Unpinned base image (latest)
Secret embedded into image layers
Remote code execution risk via curl | bash
Container runs as root
These are exactly the kinds of issues dockersec was designed to catch.
What dockersec Does
Running a scan is intentionally simple.
dockersec scan .
The scanner analyzes:
Dockerfiles
docker-compose.yml files
Custom YAML security rules
Example output:
Severity: CRITICAL
Rule: DF004
Possible secret in ENV instruction: AWS_SECRET_KEY
Fix:
Use runtime secret injection instead.
The goal isn't just finding issues.
The tool also explains:
Why the issue matters
How attackers can exploit it
How to fix it
This makes the output useful even for developers who aren't security specialists.
Current coverage includes:
20 Dockerfile rules
8 docker-compose rules
Custom YAML rules
Parsing Dockerfiles Using BuildKit AST
One design decision I made early was avoiding regular expressions for Dockerfile parsing.
Dockerfiles contain many edge cases:
RUN echo hello
RUN \
apt-get update && \
apt-get install curl
Trying to analyze these correctly using string matching quickly becomes fragile.
Instead, I used Docker's own parser from the BuildKit project.
result, err := parser.Parse(file)
The parser produces an Abstract Syntax Tree (AST).
Each instruction becomes a node that can be inspected programmatically.
for child := ast.AST.Children; child != nil; child = child.Next {
fmt.Println(child.Value)
}
This gives the scanner a structured representation of the Dockerfile rather than raw text.
Benefits:
Handles Docker syntax correctly
Easier rule implementation
Future-proof against syntax variations
Less parser maintenance
Using the same parser Docker itself relies on significantly reduced complexity.
Building the Rule Engine
Once the parser was working, I needed a clean way to organize security rules.
I wanted contributors to be able to add new rules without modifying a giant switch statement.
The solution was a self-registration pattern.
Each rule registers itself during package initialization.
func init() {
RegisterRule(NoRootUserRule{})
}
Every rule implements a common interface.
type Rule interface {
ID() string
Severity() Severity
Check(ast *parser.Result) []Finding
}
When the scanner starts, all rules have already registered themselves.
The engine simply loops through them.
for _, rule := range rules {
findings := rule.Check(parsedFile)
}
Advantages:
Easy extensibility
Clean separation of concerns
No central registry maintenance
New rules automatically become available
This pattern is widely used in plugin systems and worked extremely well for this project.
YAML Rules: Security Rules Without Writing Go
One goal for dockersec was making community contributions easy.
Not everyone wants to write Go code.
So I added support for YAML-based rules.
Example:
id: CUSTOM001
type: dockerfile
severity: HIGH
description: |
netcat found in image
fix: |
Remove netcat
match:
instruction: RUN
contains: "nc"
Drop the file into:
rules/dockerfile/
and dockersec loads it automatically.
No compilation required.
This approach allows:
Security teams to create internal policies
Contributors to add rules quickly
Organizations to enforce custom standards
without touching application code.
Shipping Releases with GoReleaser
I wanted installation to be as simple as possible.
Users shouldn't need Go installed.
They should be able to download a binary and run it.
For releases I chose GoReleaser.
A single tag push generates builds for:
Linux
macOS
Windows
Example release workflow:
- name: Release uses: goreleaser/goreleaser-action@v6
Combined with GitHub Actions, publishing a new version became completely automated.
The release pipeline:
Push a tag
GitHub Actions starts
GoReleaser builds binaries
Release assets are uploaded automatically
This significantly reduced maintenance overhead.
CI/CD Integration
dockersec can also act as a security gate.
dockersec scan . --fail-on HIGH
If a HIGH or CRITICAL issue exists, the command exits with code 1.
That means GitHub Actions can block merges automatically.
- name: Scan run: dockersec scan . --fail-on HIGH
This allows teams to enforce security checks before code reaches production.
Lessons Learned
Building dockersec taught me several things:
Parsing structured files is usually better than regexes.
Small focused CLIs can solve real problems.
Self-registering plugins keep codebases maintainable.
GoReleaser dramatically simplifies distribution.
Good error messages are as important as detection logic.
Most importantly, security tooling doesn't need to be complicated to be useful.
Sometimes a fast, local, developer-friendly tool provides more value than an enterprise platform.
Try It Out
dockersec is fully open source and available on GitHub.
Repository:
https://github.com/Deepak-coder80/dockersec
Project Page:
https://deepakms.com/projects/dockersec.html
If you find it useful, feel free to open issues, suggest new rules, or contribute improvements.
I'd love to hear feedback from the DevOps, Platform Engineering, and Security communities.

Top comments (0)