openskills.info

Build Pipeline Security

itSoftware supply chain security

Build Pipeline Security

A build pipeline turns a source revision into something people can run. It may compile code, fetch dependencies, run tests, package files, publish artifacts, and deploy a release. Each step carries trust from one system to the next.

That trust makes the pipeline a security boundary. A compromised build can produce malicious software from clean source. A stolen deployment credential can turn a test job into production access. A changed dependency or reusable pipeline component can alter many releases at once.

Build pipeline security protects the path from approved source to released artifact. You control who and what may enter that path. You limit what each job can do. You preserve evidence about what happened. You verify that evidence before accepting the output.

The pipeline as a chain of trust

A typical path looks like this:

source revision
      ↓
pipeline definition
      ↓
build platform and runner
      ↓
dependencies, tools, and configuration
      ↓
artifact and provenance
      ↓
registry, promotion, and deployment

Every arrow crosses a trust boundary. The pipeline must authenticate its input, constrain its execution, and identify its output. A green status icon only says that configured jobs reported success. It does not prove that the configuration was authorized or that the runner was trustworthy.

Treat the pipeline as production infrastructure. It often holds repository tokens, package credentials, signing authority, cloud identities, and deployment access. Its configuration deserves review, change control, monitoring, and recovery planning.

Begin with a threat model

List the assets an attacker would want:

  • source code and pipeline definitions;
  • credentials, signing identities, and secret values;
  • build workers and control-plane administration;
  • dependency and tool inputs;
  • artifacts, attestations, and registry records;
  • deployment targets and approval records.

Then trace the ways untrusted data reaches those assets. Pull requests, issue text, branch names, archive contents, build logs, test fixtures, and downloaded dependencies may all be attacker-controlled. A command that interpolates such data can become command injection. A job that runs unreviewed code with secrets can disclose them.

NSA and CISA group CI/CD risks around insecure code, poisoned pipeline execution, insufficient access controls, dependency abuse, compromised third-party services, and exposed secrets. This model helps you ask a practical question at each step: what can this input influence, and what authority exists when it does?

Separate change evaluation from release authority

Pull-request jobs need to compile and test untrusted changes. Release jobs need credentials that publish or deploy. Combining both roles gives unreviewed code a route to high-value authority.

Separate them instead:

  1. Run untrusted changes without release secrets and with minimal repository permissions.
  2. Require review and protected-branch policy before a change becomes release input.
  3. Build the release from the accepted revision in a trusted workflow.
  4. Promote the same identified artifact rather than rebuilding it in each environment.

This separation limits what a malicious contribution can reach. It also creates a clean point where policy can decide which revision is authorized for release.

Control the source and pipeline definition

The pipeline definition is executable production policy. Protect it as carefully as application code.

Require review for changes to build scripts, dependency manifests, reusable workflow references, release configuration, and ownership rules. Protect release branches and tags. Restrict who can bypass those controls. Record administrative changes.

Review is not a complete defense. An authorized account can still be compromised, and reviewers can miss dangerous behavior. Combine review with automated policy, scoped identity, isolated execution, and artifact verification.

Minimize job authority

Give every job only the permissions it needs for its current task. A test job usually does not need registry write access. A packaging job does not automatically need production deployment access. A release job should not receive every organizational secret.

Prefer short-lived workload identity over a shared, long-lived credential when the platform supports it. Bind that identity to specific conditions, such as the repository, trusted branch, workflow, job, and target environment. Keep credentials out of source, configuration, caches, artifacts, and logs.

Place approval before the job receives sensitive authority. An approval after a credential has already entered an attacker-controlled job provides little protection.

Isolate each build

A runner executes build steps. If state survives between runs, one build may influence another through files, processes, caches, credentials, or modified tools.

Use fresh workers for sensitive builds. Remove job state after use. Separate trust zones, such as public contribution testing and production release work. Restrict network paths and administrative access. Patch the worker image and the build platform.

Isolation and reproducibility solve different problems. Isolation prevents one build from influencing another. Reproducibility asks whether equivalent inputs can produce equivalent output. A reproducible build can still run on a compromised worker. An isolated build can still fetch an unexpected dependency.

SLSA Build Level 3 requires strong controls that prevent runs from influencing each other. It also keeps provenance-signing secrets outside user-defined build steps. These are platform properties, not settings a project can claim from a pipeline file alone.

Control every input

A source revision is only one build input. Compilers, base images, packages, reusable actions, plugins, scripts, and remote downloads can all change the result.

Use immutable identifiers where the ecosystem supports them. Lock dependency resolution. Verify downloaded content. Restrict allowed registries and network destinations. Review changes to lockfiles and pipeline components. Maintain an inventory so you can find affected builds when an input is compromised.

Pinning reduces unexpected change, but it also freezes defects. Pair immutable references with an update process that evaluates and advances them. A permanently old dependency is stable, not safe.

Produce and verify evidence

An artifact digest identifies exact bytes. Provenance describes how an artifact was produced, including the builder, build process, and inputs. A signature or another authentication mechanism can protect the provenance from undetected change.

SLSA divides build assurance into levels:

  • Build Level 1: provenance exists;
  • Build Level 2: a hosted build platform generates and authenticates provenance;
  • Build Level 3: the platform adds strong isolation and protects provenance-signing secrets from build steps.

Evidence is useful only when a consumer verifies it against expectations. A deployment policy might require the expected builder, source repository, trusted revision process, and subject digest. Storing an attestation without checking it creates documentation, not enforcement.

Keep artifact identity stable through promotion. Build once, identify the result by digest, and move that same result through testing and deployment. Rebuilding creates a new artifact that needs its own evidence.

Put security checks in context

Static analysis, dependency analysis, secret detection, and tests can stop known classes of defects. They do not establish that the runner was isolated, that an administrator was trustworthy, or that the published artifact matches the tested artifact.

Use checks as policy inputs. Define which findings block a release, who may approve an exception, how that decision expires, and where the record is kept. Protect the checker and its configuration from the code it evaluates.

Fail closed at release boundaries. If required provenance, identity, or policy evaluation is unavailable, hold the release. A silent bypass turns a control outage into an attack path.

Monitor and recover

Record source events, pipeline-definition changes, administrative actions, credential use, job identity, runner allocation, artifact publication, provenance generation, approvals, and deployment decisions. Protect logs from the workloads they describe and retain them long enough to investigate a release.

Prepare for compromise before it happens. Know how to disable a workflow, revoke credentials, quarantine runners, block an artifact digest, rebuild from trusted inputs, and identify every environment that received a release.

Security does not end when a job turns green. It ends when you can explain which source entered, which trusted process ran, which exact artifact emerged, which policy accepted it, and how you would contain it.

Where this course fits

This course gives you a vendor-neutral mental model for protecting build and release automation. It does not replace platform hardening guides, a full software supply chain risk program, or an incident-response plan.

Your next steps are to map one real pipeline, classify its trust boundaries, reduce job permissions, separate untrusted evaluation from release, and add verifiable provenance. Use the linked NIST, NSA and CISA, and SLSA material to turn that map into requirements.