AppScan
Product · Infrastructure

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.

01Families

38 rules, by file type.

Kubernetes
7 rules

Root pods, privilege escalation, missing limits, secrets in manifests, host mounts, default API tokens, unpinned images.

Terraform and cloud
7 rules

Public buckets and databases, ingress open to the world, IAM wildcards, storage without encryption at rest, shared snapshots.

GitHub Actions
6 rules

Untrusted checkouts, script injection, over-permissioned tokens, unpinned actions, inherited secrets, self-hosted runners on public repositories.

Dockerfile
5 rules

Root users, unpinned base images, secrets baked into layers, remote scripts piped to a shell, archives downloaded with ADD.

nginx
5 rules

Version disclosure, directory listings, weak TLS protocols, a forwarded client Host header, unlimited request bodies.

Compose and containers
4 rules

Privileged services, a mounted Docker socket, shared host namespaces, dangerous Linux capabilities.

Configuration files
3 rules

Secrets in plaintext configuration, debug mode left on in production, documented default passwords.

Network
1 rule

A database port published to the host.

02Pipelines

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.

.github/workflows/pr.yml2 findings
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 }}"
  • Critical
    A fork's code runs with your secrets
    infra.actions.untrusted-checkout
  • High
    A pull request title is pasted into a shell
    infra.actions.script-injection
03Containers

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.

04Recognised, not analysed

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.