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.
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.
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.
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.
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.
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.
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.
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.
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]
The IaC scanner runs 100% offline and fires automatically when it detects an infra file. It maps the same patterns an attacker probes for:
USER (root container), FROM :latest, hardcoded ENV secrets, COPY . . that may pull in .env and .git, and a missing HEALTHCHECK./var/run/docker.sock, default credentials like POSTGRES_PASSWORD=password, privileged: true, and a missing restart policy. Dev and local compose files get a sensible severity downgrade.AdministratorAccess / Action = "*" IAM, unencrypted RDS, hardcoded secrets in HCL (which also leak into the state file), and security groups open to 0.0.0.0/0, with SSH and RDP treated as Critical.github.event input, pull_request_target with checkout, hardcoded secrets (entropy- and placeholder-filtered so CI fixtures don't fire), third-party actions pinned to a mutable ref instead of a SHA, and write-all token permissions.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.
Before you ship, walk this list. Most of these map directly to checks above.
:latest, and add a .dockerignore so .env, .git, and key files stay out.0.0.0.0, and restrict security-group ingress to known CIDR ranges. Use a bastion or SSM for admin access.HEALTHCHECK, K8s liveness and readiness) and a restart policy so a crash recovers instead of going dark.run: steps, and pin third-party actions to a commit SHA.Scan your code and full git history in under a minute. Free verdict, no signup, nothing leaves your machine.