The files that decide how it is really deployed.
Application code is half of the story. The other half is the Dockerfile, the Compose file, the nginx config, the Kubernetes manifests, the Terraform and the workflow that deploys them - read by 38 deterministic rules on every push.
38 rules, by file type.
Root pods, privilege escalation, missing limits, secrets in manifests, host mounts, default API tokens, unpinned images.
Public buckets and databases, ingress open to the world, IAM wildcards, storage without encryption at rest, shared snapshots.
Untrusted checkouts, script injection, over-permissioned tokens, unpinned actions, inherited secrets, self-hosted runners on public repositories.
Root users, unpinned base images, secrets baked into layers, remote scripts piped to a shell, archives downloaded with ADD.
Version disclosure, directory listings, weak TLS protocols, a forwarded client Host header, unlimited request bodies.
Privileged services, a mounted Docker socket, shared host namespaces, dangerous Linux capabilities.
Secrets in plaintext configuration, debug mode left on in production, documented default passwords.
A database port published to the host.
The workflow is code that runs with your secrets.
A workflow triggered by a pull request from a fork, that checks out the fork's code and runs it with the repository's secrets, is the most common way a pipeline is taken over. So is a pull request title pasted into a shell.
- Untrusted checkout
pull_request_target with a checkout of the head ref: the fork decides what your job runs.
- Script injection
An event field - a title, a branch name, a comment - interpolated straight into a run step.
- Unpinned actions
An action referenced by a moving tag instead of a commit, so its owner can change what your job does.
- Over-broad tokens and inherited secrets
A workflow that asks for write-all when it only needs to read, or a reusable workflow handed every secret with secrets: inherit.
on:
pull_request_target:
jobs:
test:
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.event.pull_request.head.sha }}
- run: |
echo "${{ github.event.pull_request.title }}"- CriticalA fork's code runs with your secretsinfra.actions.untrusted-checkout
- HighA pull request title is pasted into a shellinfra.actions.script-injection
What the container gives away.
A process that runs as root, a database port published to every interface, a secret copied into an image layer: each is one line in a file the app never reads, and each is a rule here.
What we do not claim.
GitLab CI, CircleCI, Bitbucket Pipelines, Jenkins and Azure Pipelines files are recognised and recorded as facts about the app, but only GitHub Actions workflows are analysed. Helm charts, CloudFormation and Pulumi are not read, and container images are not scanned for CVEs. A capability that is missing is listed as missing, not implied.
Read your deploy files.
Connect one repository. The first inventory reads every infrastructure file it finds and says which lines to change.