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.
| Property | Question it answers | Example failure |
|---|---|---|
| Ephemeral | Does each build start from a clean environment? | A runner reused across jobs keeps files |
| Isolated | Can builds touch each other while running? | Two jobs share a writable volume |
| Cache independence | Does 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.
- Is a new VM or container created for every job, and destroyed after?
- Which directories survive between jobs, if any?
- Can a job write to a cache that a later release job reads without verification?
- 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
- SLSA v1.1 build requirements (page marked retired, v1.2 is current)
Last reviewed: 19 October 2026.