Safeguard
Supply Chain•

Why does SLSA Build L3 want a fresh environment for every build?

SLSA Build L3 requires an ephemeral, isolated environment per build so one build cannot persist or influence the next. Here is the attack that rules out.

Safeguard Security Team
4 min read

At Build L3, SLSA requires an ephemeral build environment for each build because a shared, long-lived environment lets one build leave something behind for the next. If an attacker or a bad dependency can persist state, later builds and their provenance inherit the damage. A fresh environment cuts that chain.

This is one of the more concrete L3 rules, and it explains why some "we have a CI server" setups stop at L2.

What the requirement says

The v1.1 requirements page lists isolation as an L3 property. Builds must be isolated from each other, including within the same tenant project. The text says it must not be possible for one build to persist or influence the build environment of a subsequent build. Under that heading it requires that an ephemeral build environment be provisioned for each build. The page is marked retired in favor of v1.2, so check the current wording.

The attack it blocks

Picture a long-lived runner that many jobs share. Build A pulls a package whose install script drops a file into a directory the runner keeps. Build B, a release build, picks that file up. Build B produces provenance that looks normal, because the platform ran the steps it was told to run.

The poisoned input never appears in the build definition. It sits in leftover state. An ephemeral environment removes the hiding place, since the next build starts from a known image.

Persistent caches are a related risk. L3 also addresses cache poisoning by requiring that output be the same with or without a cache.

Ephemeral versus isolated

These are two ideas that the page groups together.

PropertyQuestion it answersExample failure
EphemeralDoes each build start from a clean environment?A runner reused across jobs keeps files
IsolatedCan builds touch each other while running?Two jobs share a writable volume
Cache independenceDoes output change with cache state?A tampered cache entry alters a binary

You need all three for the L3 story to hold.

How to check your own setup

Ask a few plain questions about your runners.

  1. Is a new VM or container created for every job, and destroyed after?
  2. Which directories survive between jobs, if any?
  3. Can a job write to a cache that a later release job reads without verification?
  4. Are signing secrets reachable from the steps that run your scripts? L3 says they must not be.

If you cannot answer the first two quickly, assume the answer is "no" until you test. A short test is to write a marker file in one job and look for it in the next.

Cost and trade-offs

Fresh environments are slower because dependencies must be fetched or restored each time. Teams often respond by adding a cache, which re-opens the poisoning question. A pragmatic path is to keep a cache but have release builds ignore it, or to verify cache entries by digest.

Safeguard can scan the dependencies those builds pull and gate pull requests on policy, which helps with what goes into a build while your platform team works on how builds run. The free scan is at https://gold.safeguard.sh/scan.

Quick check

Is a container per job enough to be ephemeral?

Only if the container and anything it mounts start fresh each time. A shared writable volume defeats it.

Does L2 require ephemeral environments?

In the v1.1 text, the ephemeral requirement sits under L3 isolation. L2 asks for a hosted platform.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.