IOnclad  /  Features  /  IaC + Deploy
Risk Breakdown · Infra High

Your app code can be perfect. The infra around it still ships you root.

A clean Dockerfile that runs as root, a Terraform bucket set to public-read, a CI workflow that pastes a PR title straight into a shell. These aren't bugs in your logic. They're the config that wraps your logic, and they're where most launch-day breaches actually start. The container runs, the deploy succeeds, and the door is wide open.

What it checks

IOnclad reads your infrastructure-as-code the way an attacker reads it: looking for the one line that makes everything else moot. It fires automatically when it spots these file types, with 40+ checks across the deploy surface.

Dockerfile docker-compose Terraform (.tf) GitHub Actions Nginx config root containers public buckets open security groups secrets in build args TLS enforcement

Why it's dangerous

Infra misconfig is quiet. Nothing crashes, no test goes red, and the mistake only shows up when someone is already inside. Here's what actually goes wrong.

1. The container runs as root

If your final Dockerfile stage has no USER directive, the process runs as root inside the container. That sounds contained until you remember that a container escape, or a mounted volume, or a bind into the host puts that root on the host. IOnclad checks the final stage only, so a builder stage that legitimately runs as root doesn't trigger a false alarm, but the runtime image that ships needs a non-root user.

2. Secrets get baked into image layers

A secret set with ENV API_KEY=... or copied in via COPY . . without a .dockerignore doesn't disappear at runtime. It lives in docker history and the image metadata forever. Anyone who can pull the image can read it. Same story for build args: convenient, and permanently visible.

The trap

A secret in an image layer is exactly like a secret in git history. Deleting it in a later instruction does nothing. The earlier layer still holds it, and rotating the credential is the only real fix.

3. The internet has a path to your database

A docker-compose that binds 5432:5432 publishes Postgres on every interface, not just localhost. A Terraform security group with cidr_blocks = ["0.0.0.0/0"] on port 22 means every botnet on the internet starts brute-forcing SSH within minutes of the instance going live. A public-read S3 ACL means anyone with the URL reads your data. None of these throw an error. They just work, for everyone.

4. CI is a soft underbelly

GitHub Actions runs with your secrets and, often, a write token. Interpolating github.event.pull_request.title straight into a run: step lets an attacker inject shell commands through a PR title. Pinning a third-party action to @main or @v4 lets that action's owner repoint the tag to malicious code after you reviewed it, which is exactly how the tj-actions compromise worked. pull_request_target with a checkout of PR code can leak every secret you have.

The shape of a real incident

It rarely looks dramatic. It looks like a Friday Dockerfile and a Terraform block someone copied to "make the error go away."

# Dockerfile, final stage, no USER, secret baked in
FROM node:latest            # unpinned, and now you run as root
ENV STRIPE_KEY=sk_live_51H... # lives in docker history forever
COPY . .                   # no .dockerignore: .env and .git go in too
CMD ["node","server.js"]

# Terraform, "just open it so the demo works"
ingress {
  from_port   = 22
  to_port     = 22
  cidr_blocks = ["0.0.0.0/0"] # SSH to the entire internet
}

# The fix is small and boring, which is why it gets skipped:
USER nonroot:nonroot
cidr_blocks = [var.office_cidr]
How IOnclad catches it

The IaC scanner runs 100% offline and fires automatically when it detects an infra file. It maps the same patterns an attacker probes for:

IOnclad finds known patterns and common misconfigurations. It is not a pentest or a guarantee, but it surfaces the deploy mistakes that get found first, with the exact file and line.

The deploy-readiness checklist

Before you ship, walk this list. Most of these map directly to checks above.

Find every secret before someone else does.

Scan your code and full git history in under a minute. Free verdict, no signup, nothing leaves your machine.