DEV Community

DEEPAK M S
DEEPAK M S

Posted on

I Built an Offline Docker Security Scanner in Go Parsing Dockerfiles, Building a Rule Engine, and Shipping a Cross-Platform CLI

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)