SLSA is a specification for describing and incrementally improving supply chain
security, established by industry consensus. It is organized into a series of
levels that describe increasing security guarantees.
This is version 1.0-rc1 of the SLSA specification, which defines the SLSA
levels. For other versions, use the chooser to
the rightat the bottom of this section. For
the recommended attestation formats, including provenance, see “Specifications”
in the menu at the top.
About this release candidate
This release candidate is a preview of version 1.0. It contains all
anticipated concepts and major changes for v1.0, but there are still outstanding
TODOs and cleanups. We expect to cover all TODOs and address feedback before the
1.0 final release.
Known issues:
-
TODO: Use consistent terminology throughout the site: “publish” vs
“release”, “publisher” vs “maintainer” vs “developer”, “consumer” vs
“ecosystem” vs “downstream system”, “build” vs “produce.
-
Verifying artifacts and setting expectations are still in flux. We would
like feedback on whether to move these parts out of the build track.
Table of contents
Section |
Description |
What’s new in v1.0 |
What’s new in SLSA Version 1.0. |
Security levels |
Overview of SLSA, intended for all audiences. If you read one section, read this. |
Guiding principles |
Background on the guiding principles behind SLSA. |
Terminology |
Terminology and model used by SLSA. |
Producing artifacts |
Detailed technical requirements for producing software artifacts, intended for system implementers. |
Verifying build systems |
Guidelines for securing SLSA Build L3+ builders, intended for system implementers. |
Verifying artifacts |
Guidance for verifying software artifacts and their SLSA provenance, intended for system implementers and software consumers. |
Threats & mitigations |
Specific supply chain attacks and how SLSA helps. |
FAQ |
Questions and more information. |
Future directions |
Additions and changes being considered for future SLSA versions. |
Security levels
SLSA is organized into a series of levels that provide increasing supply chain
security guarantees. This gives you confidence that software hasn’t been
tampered with and can be securely traced back to its source.
This section is an informative overview of the SLSA levels, describing their
purpose and guarantees. For the normative requirements at each level, see
Requirements. For a background, see
Terminology.
What is SLSA?
SLSA is a set of incrementally adoptable security guidelines, established by
industry consensus. The standards set by SLSA are guiding principles for both
software producers and consumers: producers can follow the guidelines to make
their software more secure, and consumers can make decisions based on a software
package’s security posture. SLSA’s levels are designed to be incremental
and actionable, and to protect against specific classes of supply chain attacks.
The highest level in each track represents an ideal end state, and the lower
levels represent intermediate milestones with commensurate security guarantees.
Importantly, SLSA is intended to be a primitive in a broader determination of a
software’s risk. SLSA measures specific aspects of supply chain security,
particularly those that can be fully automated; other aspects, such as developer
trust and code quality, are out of scope. Furthermore, each link in the software
supply chain has its own, independent SLSA level—in other words, it is not
transitive (FAQ). The benefit of this
approach is to break up the large supply chain security problem into tractable
subproblems that can be prioritized based on risk and tackled in parallel. But
this does mean that SLSA alone is not sufficient to determine if an artifact is
“safe”.
Finally, SLSA is in the eye of the beholder: software consumers ultimately make
their own SLSA determinations, though in practice they may delegate to some
authority. For example, a build system may claim to conform to SLSA Build L3,
but it is up to a consumer whether to trust that claim.
Who is SLSA for?
SLSA is intended to serve multiple populations:
-
Project maintainers, who are often small teams that know their build
process and trust their teammates. Their primary goal is protection against
compromise with as low overhead as possible. They may also benefit from
easier maintenance and increased consumer confidence.
-
Consumers, who use a variety of software and do not know the maintainers
or their build processes. Their primary goal is confidence that the software
has not been tampered with. They are concerned about rogue maintainers,
compromised credentials, and compromised infrastructure.
-
Organizations, who are both producers and consumers of software. In
addition to the goals above, organizations also want to broadly understand
and reduce risk across the organization.
-
Infrastructure providers, such as build services and package
ecosystems, who are critical to achieving SLSA. While not the primary
beneficiary of SLSA, they may benefit from increased security and user
trust.
Levels and tracks
SLSA levels are split into tracks. Each track has its own set of levels that
measure a particular aspect of supply chain security. The purpose of tracks is
to recognize progress made in one aspect of security without blocking on an
unrelated aspect. Tracks also allow the SLSA spec to evolve: we can add more
tracks without invalidating previous levels.
Track/Level |
Requirements |
Benefits |
Build L0 |
(none) |
(n/a) |
Build L1 |
Attestation showing that the package was built as expected |
Documentation, mistake prevention, inventorying |
Build L2 |
Signed attestation, generated by a hosted build service |
Reduced attack surface, weak tamper protection |
Build L3 |
Hardened build service |
Strong tamper protection |
Note: The previous version of the specification used a single unnamed track,
SLSA 1–4. For version 1.0 the Source aspects were removed to focus on the
Build track. A Source track may be added in future versions.
Build track
The SLSA build track describes the level of protection against tampering
during or after the build, and the trustworthiness of provenance metadata.
Higher SLSA build levels provide increased confidence that a package truly came
from the correct sources, without unauthorized modification or influence.
TODO: Add a diagram visualizing the following.
Summary of the build track:
- Set project-specific expectations for how the package should be built.
- Generate a provenance attestation automatically during each build.
- Automatically verify that each package’s provenance meets expectations
before allowing its publication and/or consumption.
What sets the levels apart is how much trust there is in the accuracy of the
provenance and the degree to which adversaries are detected or prevented from
tampering with the package. Higher levels require hardened builds and protection
against more sophisticated adversaries.
Each ecosystem (for open source) or organization (for closed source) defines
exactly how this is implemented, including: means of defining expectations, what
provenance format is accepted, whether reproducible builds are used, how
provenance is distributed, when verification happens, and what happens on
failure. Guidelines for implementers can be found in the
requirements.
Build L0: No guarantees
- Summary
-
No requirements—L0 represents the lack of SLSA.
- Intended for
-
Development or test builds of software that are built and run on the same
machine, such as unit tests.
- Requirements
-
n/a
- Benefits
-
n/a
Build L1: Provenance
- Summary
-
Package has a provenance attestation showing how it was built, and a downstream
system automatically verifies that packages were built as expected. Prevents
mistakes but is trivial to bypass or forge.
- Intended for
-
Projects and organizations wanting to easily and quickly gain some benefits of
SLSA—other than tamper protection—without changing their build workflows.
- Requirements
-
-
Up front, the package maintainer defines how the package is expected to be
built, including the canonical source repository and build command.
-
On each build, the release process automatically generates and distributes a
provenance attestation describing how the artifact was actually built,
including: who built the package (person or system), what process/command
was used, and what the input artifacts were.
-
Downstream tooling automatically verifies that the artifact’s provenance
exists and matches the expectation.
- Benefits
-
-
Makes it easier for both maintainers and consumers to debug, patch, rebuild,
and/or analyze the software by knowing its precise source version and build
process.
-
Prevents mistakes during the release process, such as building from a commit
that is not present in the upstream repo.
-
Aids organizations in creating an inventory of software and build systems
used across a variety of teams.
- Notes
-
- Provenance may be incomplete and/or unsigned at L1. Higher levels require
more complete and trustworthy provenance.
Build L2: Build service
- Summary
-
Forging the provenance or evading verification requires an explicit “attack”,
though this may be easy to perform. Deters unsophisticated adversaries or those
who face legal or financial risk.
In practice, this means that builds run on a hosted service that generates and
signs the provenance.
- Intended for
-
Projects and organizations wanting to gain moderate security benefits of SLSA by
switching to a hosted build service, while waiting for changes to the build
service itself required by Build L3.
- Requirements
-
All of Build L1, plus:
-
The build runs on a hosted build service that generates and signs the
provenance itself. This may be the original build, an after-the-fact
reproducible build, or some equivalent system that ensures the
trustworthiness of the provenance.
-
Downstream verification of provenance includes validating the authenticity
of the provenance attestation.
- Benefits
-
All of Build L1, plus:
-
Prevents tampering after the build through digital signatures.
-
Deters adversaries who face legal or financial risk by evading security
controls, such as employees who face risk of getting fired.
-
Reduces attack surface by limiting builds to specific build services that
can be audited and hardened.
-
Allows large-scale migration of teams to supported build services early
while further hardening work (Build L3) is done in parallel.
Build L3: Hardened builds
- Summary
-
Forging the provenance or evading verification requires exploiting a
vulnerability that is beyond the capabilities of most adversaries.
In practice, this means that builds run on a hardened build service that offers
strong tamper protection.
- Intended for
-
Most software releases. Build L3 usually requires significant changes to
existing build services.
- Requirements
-
All of Build L2, plus:
- Benefits
-
All of Build L2, plus:
-
Prevents tampering during the build—by maintainers, compromised
credentials, or other tenants.
-
Greatly reduces the impact of compromised package upload credentials by
requiring attacker to perform a difficult exploit of the build process.
-
Provides strong confidence that the package was built from the official
source and build process.
Guiding principles
This section provides a background on the guiding principles behind SLSA. It is
intended to help the reader better understand SLSA’s design decisions.
Trust systems, verify artifacts
One of the main ideas behind SLSA is to establish trust in a small number of
systems and then automatically verify the many artifacts produced by those
systems. In this way, SLSA is able to scale to support hundreds of thousands of
software projects with a near-constant amount of central work.
We have no option but to manually analyze and reason about the behavior of some
number of trusted systems, such as change management, build, and packaging
systems. There will always be some trusted computing base on which we rely for
security. We need to analyze and reason about this computing base to convince
ourselves that it meets our security needs. Such analysis is difficult and
expensive. We cannot possibly harden and audit thousands of bespoke build
systems. We can, however, do this for a small number of general purpose systems.
Once we have a set of trusted systems, we can verify the supply chain of
arbitrarily many artifacts by ensuring that artifacts were produced by trusted
systems. This allows SLSA to scale to entire ecosystems and organizations
regardless of size.
For example, a security engineer may analyze the architecture and implementation
of a build system to ensure that it meets the SLSA build requirements. Once the
analysis is complete, the public keys used by the build system to sign
provenance can then be “trusted” up to a given SLSA level. Downstream systems
can then automatically determine that an artifact meets a given level by
verifying that it has provenance signed by that public key.
Corollary: Minimize the number of trusted systems
A corollary to the previous principle is to minimize the size of the trusted
computing base. Every system we trust adds attack surface and increases the need
for manual security analysis. Where possible:
- Concentrate trust in shared infrastructure. For example, instead of each
team maintaining their own build system, use a shared build system. This way
hardening work can be shared across all teams.
- Remove the need to trust components whenever possible. For example, use
end-to-end signing to avoid the need to trust intermediate distribution
systems.
Anchor trust in code, not individuals
Another idea behind SLSA is to anchor our trust in source code rather than
individual maintainers who have write access to package registries. Code is
static and analyzable. People, on the other hand, are prone to mistakes,
credential compromise, and sometimes malicious action. Therefore, SLSA aims to
securely trace all software back to source code, without the possibility for an
individual maintainer to tamper with it after it has been committed.
Prefer attestations over inferences
SLSA places a strong emphasis on explicit attestations about security
properties, particularly an artifact’s provenance, rather than inferring
security properties from how a system is configured.
Theoretically one could configure access control such that the only path from
source to release is through the official channels: the CI/CD system only pulls
from the proper source, package registry only allows access to the CI/CD system,
and so on. In practice, that is almost impossible to get right and keep right.
There are often over-provisioning, confused deputy problems, or mistakes. Even
if it is configured properly at one moment, there is no guarantee that it will
continue to stay so. And humans almost always end up getting in the access
control lists.
Instead, SLSA prefers explicit attestations about an artifact’s provenance.
Access control is still important, but SLSA provides a defense in depth: it is
not sufficient to be granted access to publish a package; one must also have
proof in the form of attestations that a package was built correctly. This way,
the intermediate systems are taken out of the trust base and any individuals
that are accidentally granted access do not have sufficient permission to tamper
with the package.
Terminology
Before diving into the SLSA Levels, we need to establish a core set
of terminology and models to describe what we’re protecting.
TODO: Terms we still need to define
TODO: Define these terms before the v1.0 release.
Software supply chain
SLSA’s framework addresses every step of the software supply chain - the
sequence of steps resulting in the creation of an artifact. We represent a
supply chain as a directed acyclic graph of sources, builds, dependencies, and
packages. One artifact’s supply chain is a combination of its dependencies’
supply chains plus its own sources and builds.
Term |
Description |
Example |
Artifact |
An immutable blob of data; primarily refers to software, but SLSA can be used for any artifact. |
A file, a git commit, a directory of files (serialized in some way), a container image, a firmware image. |
Attestation |
An authenticated statement (metadata) about a software artifact or collection of software artifacts. |
A signed SLSA Provenance file. |
Source |
Artifact that was directly authored or reviewed by persons, without modification. It is the beginning of the supply chain; we do not trace the provenance back any further. |
Git commit (source) hosted on GitHub (platform). |
Build |
Process that transforms a set of input artifacts into a set of output artifacts. The inputs may be sources, dependencies, or ephemeral build outputs. |
.travis.yml (process) run by Travis CI (platform). |
Package |
Artifact that is “published” for use by others. In the model, it is always the output of a build process, though that build process can be a no-op. |
Docker image (package) distributed on DockerHub (platform). A ZIP file containing source code is a package, not a source, because it is built from some other source, such as a git commit. |
Dependency |
Artifact that is an input to a build process but that is not a source. In the model, it is always a package. |
Alpine package (package) distributed on Alpine Linux (platform). |
Build model
We model a build as running on a multi-tenant platform, where each execution is
independent. A tenant defines the build by specifying parameters through some
sort of external interface, often including a reference to a configuration file
in source control. The platform then runs the build by interpreting the
parameters, fetching some initial set of dependencies, initializing the build
environment, and then starting execution. The build then performs arbitrary
steps, possibly fetching additional dependencies, and outputs one or more
artifacts. Finally, for SLSA Build L2+, the platform outputs provenance
describing this whole process.
Primary Term |
Description |
Platform |
System that allows tenants to run builds. Technically, it is the transitive closure of software and services that must be trusted to faithfully execute the build. |
Build |
Process that converts input sources and dependencies into output artifacts, defined by the tenant and executed within a single environment on a platform. |
Steps |
The set of actions that comprise a build, defined by the tenant. |
Environment |
Machine, container, VM, or similar in which the build runs, initialized by the platform. In the case of a distributed build, this is the collection of all such machines/containers/VMs that run steps. |
External parameters |
The set of top-level, independent inputs to the build, specified by a tenant and used by the platform to initialize the build. |
Dependencies |
Artifacts fetched during initialization or execution of the build process, such as configuration files, source artifacts, or build tools. |
Outputs |
Collection of artifacts produced by the build. |
Provenance |
Attestation (metadata) describing how the outputs were produced, including identification of the platform and external parameters. |
Notably, there is no formal notion of “source” in the build model, just
parameters and dependencies. Most build platforms have an explicit “source”
artifact to be built, which is often a git repository; in the build model, the
reference to this artifact is a parameter while the artifact itself is a
dependency.
For examples on how this model applies to real-world build systems, see index
of build types.
Verification model
Verification in SLSA is performed in two ways. Firstly, the build system is
certified to ensure conformance with the requirements at the level claimed by
the build system. This certification should happen on a recurring cadence with
the outcomes published by the platform operator for their users to review and
make informed decisions about which builders to trust.
Secondly, artifacts are verified to ensure they meet the producer defined
expectations of where the package source code was retrieved from and on what
build system the package was built.
Term |
Description |
Expectations |
A set of constraints on the package’s provenance metadata. The package producer sets expectations for a package, whether explicitly or implicitly. |
Provenance verification |
Artifacts are verified by the package ecosystem to ensure that the package’s expectations are met before the package is used. |
Build system certification |
Build systems are certified for their conformance to the SLSA requirements at the stated level. |
The examples below suggest some ways that expectations and verification may be
implemented for different, broadly defined, package ecosystems.
Example: Small software team
Term |
Example |
Expectations |
Defined by the producer’s security personnel and stored in a database. |
Provenance verification |
Performed automatically on cluster nodes before execution by querying the expectations database. |
Build system certification |
The build system implementer follows secure design and development best practices, does annual penetration testing exercises, and self-certifies their conformance to SLSA requirements. |
Example: Open source language distribution
Term |
Example |
Expectations |
Defined separately for each package and stored in the package registry. |
Provenance verification |
The language distribution registry verifies newly uploaded packages meet expectations before publishing them. Further, the package manager client also verifies expectations prior to installing packages. |
Build system certification |
Performed by the language ecosystem packaging authority. |
Producing artifacts
This section covers the detailed technical requirements for producing artifacts at
each SLSA level. The intended audience is system implementers and security
engineers.
For an informative description of the levels intended for all audiences, see
Levels. For background, see Terminology. To
better understand the reasoning behind the requirements, see
Threats and mitigations.
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”,
“SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be
interpreted as described in RFC 2119.
Overview
Build levels
Responsibility to implement SLSA is spread across the following parties.
Security Best Practices
While the exact definition of what constitutes a secure system is beyond the
scope of this specification, to be conformant all implementations MUST use
industry security best practices. This includes, but is not limited to, using
proper access controls, securing communications, implementing proper management
of cryptographic secrets, doing frequent updates, and promptly fixing known
vulnerabilities.
Various relevant standards and guides can be consulted for that matter such as
the CIS Critical Security
Controls.
Producer
A package’s producer is the organization that owns and releases the
software. It might be an open-source project, a company, a team within a
company, or even an individual.
Choose an appropriate build system
The producer MUST select a build system that is capable of reaching their
desired SLSA Build Level.
For example, if a producer wishes to produce a Build Level 3 artifact, they MUST
choose a builder capable of producing Build Level 3 provenance.
Follow a consistent build process
The producer MUST build their artifact in a consistent
manner such that verifiers can form expectations about the build process. In
some implementations, the producer MAY provide explicit metadata to a verifier
about their build process. In others, the verifier will form their expectations
implicitly (e.g. trust on first use).
For example, if a producer wishes to distribute their artifact through a package
ecosystem that requires explicit metadata about the build process in the form of
a config file. That metadata includes the artifact’s source repository and build
parameters that stay constant between builds. The producer MUST complete that
config file and keep it up to date.
Distribute provenance
The producer MUST distribute provenance to artifact consumers. The producer
MAY delegate this responsibility to the package ecosystem, provided that the
package ecosystem is capable of distributing provenance.
Build system
A package’s build system is the infrastructure used to transform the
software from source to package. This includes the transitive closure of all
hardware, software, persons, and organizations that can influence the build. A
build system is often a hosted, multi-tenant build service, but it could be a
system of multiple independent rebuilders, a special-purpose build system used
by a single software project, or even a developer’s workstation. Ideally, one
build system is used by many different software packages so that consumers can
minimize the number of trusted systems. For more background,
see Build Model.
The build system is responsible for providing two things: provenance
generation and isolation between builds. The Build level describes
the degree to which each of these properties is met.
Provenance generation
The build system is responsible for generating provenance describing how the
package was produced.
The SLSA Build level describes the minimum bound for:
- Completeness: What information is contained in the provenance?
- Authenticity: How strongly can the provenance be tied back to the builder?
- Accuracy: How resistant is the provenance generation to tampering within
the build process?
Requirement | Description | L1 | L2 | L3
|
---|
Provenance Exists |
The build process MUST generate provenance that unambiguously identifies the
output package and describes how that package was produced.
The format MUST be acceptable to the
package ecosystem and/or
consumer. It
is RECOMMENDED to use the SLSA Provenance format and associated suite
because it is designed to be interoperable, universal, and unambiguous when
used for SLSA. See that format’s documentation for requirements and
implementation guidelines. If using an alternate format, it MUST contain the
equivalent information as SLSA Provenance at each level and SHOULD be
bi-directionally translatable to SLSA Provenance.
- Completeness: Best effort. The provenance at L1 SHOULD contain sufficient
information to catch mistakes and simulate the user experience at higher
levels in the absence of tampering. In other words, the contents of the
provenance SHOULD be the same at all Build levels, but a few fields MAY be
absent at L1 if they are prohibitively expensive to implement.
- Authenticity: No requirements.
- Accuracy: No requirements.
| ✓ | ✓ | ✓
|
Provenance is Authentic |
Authenticity: Consumers MUST be able to validate the authenticity of the
provenance attestation in order to:
- Ensure integrity: Verify that the digital signature of the provenance
attestation is valid and the provenance was not tampered with after the
build.
- Define trust: Identify the build system and other entities that are
necessary to trust in order to trust the artifact they produced.
This SHOULD be through a digital signature from a private key accessible only to
the service that generated the provenance attestation.
This allows the consumer to trust the contents of the provenance attestation,
such as the identity of the build system.
Accuracy: The provenance MUST be generated by the build system (i.e. within
the trust boundary identified in the provenance) and not by a tenant of the
build system (i.e. outside the trust boundary).
- The data in the provenance MUST be obtained from the build service, either
because the generator is the build service or because the provenance
generator reads the data directly from the build service.
- The build system MUST have some security control to prevent tenants from
tampering with the provenance. However, there is no minimum bound on the
strength. The purpose is to deter adversaries who might face legal or
financial risk from evading controls.
Completeness: SHOULD be complete, but there MAY be external parameters that
are not sufficiently captured in the provenance.
| | ✓ | ✓
|
Provenance is Non-forgeable |
Accuracy: Provenance MUST be strongly resistant to influence by tenants.
- Any secret material used to demonstrate the non-forgeable nature of
the provenance, for example the signing key used to generate a digital
signature, MUST be stored in a secure management system appropriate for
such material and accessible only to the build service account.
- Such secret material MUST NOT be accessible to the environment running
the user-defined build steps.
- Every field in the provenance MUST be generated or verified by the build
service in a trusted control plane. The user-controlled build steps MUST
NOT be able to inject or alter the contents.
Completeness: MUST be complete. In particular, the external parameters MUST be
fully enumerated in the provenance.
Note: This requirement was called “non-falsifiable” in the initial
draft version (v0.1).
| | | ✓
|
Isolation strength
The build system is responsible for isolating between builds, even within the
same tenant project. In other words, how strong of a guarantee do we have that
the build really executed correctly, without external influence?
The SLSA Build level describes the minimum bar for isolation strength. For more
information on assessing a build system’s isolation strength, see
Verifying build systems.
Requirement | Description | L1 | L2 | L3
|
---|
Build service
|
All build steps ran using some build service, not on a maintainer’s
workstation.
Examples: GitHub Actions, Google Cloud Build, Travis CI.
| | ✓ | ✓
|
Ephemeral and isolated
|
The build service ensured that the build steps ran in an ephemeral and isolated
environment provisioned solely for this build, free of influence from other
build instances, whether prior or concurrent.
- It MUST NOT be possible for a build to access any secrets of the build service, such as the provenance signing key.
- It MUST NOT be possible for two builds that overlap in time to influence one another.
- It MUST NOT be possible for one build to persist or influence the build environment of a subsequent build.
- Build caches, if used, MUST be purely content-addressable to prevent tampering.
- The build SHOULD NOT call out to remote execution unless it’s considered part of the “builder” within the trust boundary.
- The build SHOULD NOT open services that allow for remote influence.
Note: This requirement was split into “Isolated” and “Ephemeral Environment” the
initial draft version (v0.1).
| | | ✓
|
Verifying Build Systems
The provenance consumer is responsible for deciding whether they trust a builder to produce SLSA Build L3 provenance. However, assessing Build L3 capabilities requires information about a builder’s construction and operating procedures that the consumer cannot glean from the provenance itself. To aid with such assessments, we provide a common threat model and builder model for reasoning about builders’ security. We also provide a questionnaire that organizations can use to describe their builders to consumers along with sample answers that do and do not satisfy the SLSA Build L3 requirements.
Threat Model
Attacker Goal
The attacker’s primary goal is to tamper with a build to create unexpected, vulnerable, or malicious behavior in the output artifact while avoiding detection. Their means of doing so is generating build provenance that does not faithfully represent the built artifact’s origins or build process.
More formally, if a build with external parameters P would produce an artifact with binary hash X and a build with external parameters P’ would produce an artifact with binary hash Y, they wish to produce provenance indicating a build with external parameters P produced an artifact with binary hash Y.
This diagram represents a successful attack:
Note: Platform abuse (e.g. running non-build workloads) and attacks against builder availability are out of scope of this document.
TODO: Align/cross-reference with SLSA Provenance Model.
TODO: Redraw diagrams in the style used by the rest of the site.
Types of attackers
We consider three attacker profiles differentiated by the attacker’s capabilities and privileges as related to the build they wish to subvert (the “target build”).
TODO: Tie attack profiles into the rest of this section.
Project contributors
Capabilities:
- Create builds on the build service. These are the attacker’s controlled builds.
- Modify one or more controlled builds’ external parameters.
- Modify one or more controlled builds’ environments and run arbitrary code inside those environments.
- Read the target build’s source repo.
- Fork the target build’s source repo.
- Modify a fork of the target build’s source repo and build from it.
Project maintainer
Capabilities:
- All listed under “low privilege”.
- Create new builds under the target build’s project or identity.
- Modify the target build’s source repo and build from it.
- Modify the target build’s configuration.
Build service admin
Capabilities:
- All listed under “low privilege” and “medium privilege”.
- Run arbitrary code on the build service.
- Read and modify network traffic.
- Access the control plane’s cryptographic secrets.
- Remotely access build executors (e.g. via SSH).
TODO: List other high-privilege capabilities.
TODO: Maybe differentiate between unilateral and non-unilateral privileges.
Build Model
The build model consists of five components: parameters, the control plane, one or more build executors, a build cache, and output storage. The data flow between these components is shown in the diagram below.
TODO: Align with provenance and build models.
The following subsections detail each element of the build model and prompts for assessing its ability to produce SLSA Build L3 provenance.
External Parameters
External parameters are the external interface to the builder and include all inputs to the build process. Examples include the source to be built, the build definition/script to be executed, user-provided instructions to the control plane for how to create the build executor (e.g. which operating system to use), and any additional user-provided strings.
Prompts for Assessing External Parameters
- How does the control plane process user-provided external parameters? Examples: sanitizing, parsing, not at all
- Which external parameters are processed by the control plane and which are processed by the executor?
- What sort of external parameters does the control plane accept for executor configuration?
- How do you ensure that all external parameters are represented in the provenance?
- How will you ensure that future design changes will not add additional external parameters without representing them in the provenance?
Control Plane
The control plane is the build system component that orchestrates each independent build execution. It is responsible for setting up each build and cleaning up afterwards. At SLSA Build L2+ the control plane generates and signs provenance for each build performed on the build service. The control plane is operated by one or more administrators, who have privileges to modify the control plane.
Prompts for Assessing Control Planes
Executor
The build executor is the independent execution environment where the build takes place. Each executor must be isolated from the control plane and from all other executors, including executors running builds from the same build user or project. Build users are free to modify the environment inside the executor arbitrarily. Build executors must have a means to fetch input artifacts (source, dependencies, etc).
Prompts for Assessing Executors
-
Isolation technologies
- How are executors isolated from the control plane and each other? Examples: VMs, containers, sandboxed processes
- How have you hardened your executors against malicious tenants? Examples: configuration hardening, limiting attack surface
- How frequently do you update your isolation software?
- What is your process for responding to vulnerability disclosures? What about vulnerabilities in your dependencies?
- What prevents a malicious build from gaining persistence and influencing subsequent builds?
-
Creation and destruction
- What tools and environment are available in executors on creation? How were the elements of this environment chosen? Examples: A minimal Linux distribution with its package manager, OSX with HomeBrew
- How long could a compromised executor remain active in the build system?
-
Network access
- Are executors able to call out to remote execution? If so, how do you prevent them from tampering with the control plane or other executors over the network?
- Are executors able to open services on the network? If so, how do you prevent remote interference through these services?
Cache
Builders may have zero or more caches to store frequently used dependencies. Build executors may have either read-only or read-write access to caches.
Prompts for Assessing Caches
- What sorts of caches are available to build executors?
- How are those caches populated?
- How are cache contents validated before use?
Output Storage
Output Storage holds built artifacts and their provenance. Storage may either be shared between build projects or allocated separately per-project.
Prompts for Assessing Output Storage
- How do you prevent builds from reading or overwriting files that belong to another build? Example: authorization on storage
- What processing, if any, does the control plane do on output artifacts?
Builder Evaluation
Organizations can either self-attest to their answers or seek an audit/certification from a third party. Questionnaires for self-attestation should be published on the internet. Questionnaires for third-party certification need not be published. All provenance generated by L3+ builders must contain a non-forgeable attestation of the builder’s L3+ capabilities with a limited validity period. Any secret materials used to prove the non-forgeability of the attestation must belong to the attesting party.
TODO: Add build system attestation spec
Threats and mitigations
Attacks can occur at every link in a typical software supply chain, and these
kinds of attacks are increasingly public, disruptive, and costly in today’s
environment.
SLSA’s levels are designed to mitigate the risk of these attacks.
This section enumerates possible attacks throughout the supply chain and shows how
SLSA can help. For a background, see Terminology.
Summary
SLSA’s primary focus is supply chain integrity, with a secondary focus on
availability. Integrity means protection against tampering or unauthorized
modification at any stage of the software lifecycle. Within SLSA, we divide
integrity into source integrity vs build integrity.
Source integrity: Ensure that all changes to the source code reflect the
intent of the software producer. Intent of an organization is difficult to
define, so SLSA approximates this as approval from two authorized
representatives.
Build integrity: Ensure that the package is built from the correct,
unmodified sources and dependencies according to the build recipe defined by the
software producer, and that artifacts are not modified as they pass between
development stages.
Availability: Ensure that the package can continue to be built and
maintained in the future, and that all code and change history is available for
investigations and incident response.
Real-world examples
TODO: Update this for v1.0.
Many recent high-profile attacks were consequences of supply-chain integrity vulnerabilities, and could have been prevented by SLSA’s framework. For example:
| Integrity threat
| Known example
| How SLSA can help
|
A
| Submit unauthorized change (to source repo)
| Linux hypocrite commits: Researcher attempted to intentionally introduce vulnerabilities into the Linux kernel via patches on the mailing list.
| Two-person review caught most, but not all, of the vulnerabilities.
|
B
| Compromise source repo
| PHP: Attacker compromised PHP's self-hosted git server and injected two malicious commits.
| A better-protected source code platform would have been a much harder target for the attackers.
|
C
| Build from modified source (not matching source repo)
| Webmin: Attacker modified the build infrastructure to use source files not matching source control.
| A SLSA-compliant build server would have produced provenance identifying the actual sources used, allowing consumers to detect such tampering.
|
D
| Compromise build process
| SolarWinds: Attacker compromised the build platform and installed an implant that injected malicious behavior during each build.
| Higher SLSA levels require stronger security controls for the build platform, making it more difficult to compromise and gain persistence.
|
E
| Use compromised dependency (i.e. A-H, recursively)
| event-stream: Attacker added an innocuous dependency and then later updated the dependency to add malicious behavior. The update did not match the code submitted to GitHub (i.e. attack F).
| Applying SLSA recursively to all dependencies would have prevented this particular vector, because the provenance would have indicated that it either wasn't built from a proper builder or that the source did not come from GitHub.
|
F
| Upload modified package (not matching build process)
| CodeCov: Attacker used leaked credentials to upload a malicious artifact to a GCS bucket, from which users download directly.
| Provenance of the artifact in the GCS bucket would have shown that the artifact was not built in the expected manner from the expected source repo.
|
G
| Compromise package repo
| Attacks on Package Mirrors: Researcher ran mirrors for several popular package repositories, which could have been used to serve malicious packages.
| Similar to above (F), provenance of the malicious artifacts would have shown that they were not built as expected or from the expected source repo.
|
H
| Use compromised package
| Browserify typosquatting: Attacker uploaded a malicious package with a similar name as the original.
| SLSA does not directly address this threat, but provenance linking back to source control can enable and enhance other solutions.
|
| Availability threat
| Known example
| How SLSA can help
|
E
| Dependency becomes unavailable
| Mimemagic: Maintainer intentionally removes package or version of package from repository with no warning. Network errors or service outages may also make packages unavailable temporarily.
| SLSA does not directly address this threat.
|
A SLSA level helps give consumers confidence that software has not been tampered
with and can be securely traced back to source—something that is difficult, if
not impossible, to do with most software today.
Threats in detail
IMPORTANT: This is a work in progress.
What follows is a comprehensive technical analysis of supply chain threats and
their corresponding mitigations in SLSA. The goals are to:
- Explain the reasons for each of the SLSA requirements.
- Increase confidence that the SLSA requirements are sufficient to achieve the
desired level of integrity protection.
- Help implementers better understand what they are protecting against so that
they can better design and implement controls.
Source integrity threats
A source integrity threat is a potential for an adversary to introduce a change
to the source code that does not reflect the intent of the software producer.
This includes the threat of an authorized developer introducing an unauthorized
change—in other words, an insider threat.
SLSA v1.0 does not address source integrity, though we anticipate a Source
track might do so in a future version. In
the meantime, the threats and potential mitigations listed here show how SLSA
v1.0 can fit into a broader supply chain security program.
(A) Submit unauthorized change
An adversary introduces a change through the official source control management
interface without any special administrator privileges.
(A1) Submit change without review
Directly submit without review
Threat: Submit bad code to the source repository without another person
reviewing.
Mitigation: Source repository requires two-person approval for all changes.
Example: Adversary directly pushes a change to a GitHub repo’s main
branch.
Solution: Configure GitHub’s “branch protection” feature to require pull request
reviews on the main
branch.
Review own change through a sock puppet account
Threat: Propose a change using one account and then approve it using another
account.
Mitigation: Source repository requires approval from two different, trusted
persons. If the proposer is trusted, only one approval is needed; otherwise two
approvals are needed. The software producer maps accounts to trusted persons.
Example: Adversary creates a pull request using a secondary account and then
approves and merges the pull request using their primary account. Solution:
Configure branch protection to require two approvals and ensure that all
repository contributors and owners map to unique persons.
Use a robot account to submit change
Threat: Exploit a robot account that has the ability to submit changes without
two-person review.
Mitigation: All changes require two-person review, even changes authored by
robots.
Example: A file within the source repository is automatically generated by a
robot, which is allowed to submit without review. Adversary compromises the
robot and submits a malicious change without review. Solution: Require human
review for these changes.
RFC (#196): This solution
may not be practical. Should there be an exception for locked down robot
accounts?
Abuse review exceptions
Threat: Exploit a review exception to submit a bad change without review.
Mitigation: All changes require two-person review without exception.
Example: Source repository requires two-person review on all changes except
for “documentation changes,” defined as only touching files ending with .md
or
.html
. Adversary submits a malicious executable named evil.md
without review
using this exception, and then builds a malicious package containing this
executable. This would pass expectations because the source repository is
correct, and the source repository does require two-person review. Solution: Do
not allow such exceptions.
RFC: This solution may not be practical in all circumstances. Are there any
valid exceptions? If so, how do we ensure they cannot be exploited?
(A2) Evade code review requirements
Modify code after review
Threat: Modify the code after it has been reviewed but before submission.
Mitigation: Source control platform invalidates approvals whenever the
proposed change is modified.
Example: Source repository requires two-person review on all changes.
Adversary sends a “good” pull request to a peer, who approves it. Adversary then
modifies it to contain “bad” code before submitting. Solution: Configure branch
protection to dismiss stale approvals when new changes are pushed.
RFC: How do we handle the productivity hit? The cost of code review is already
high for most projects, given current code review tooling, so making code
review even costlier might not be considered warranted. Are there alternative
solutions? Better tooling? Another SLSA level to represent this?
Submit a change that is unreviewable
Threat: Send a change that is meaningless for a human to review that looks
benign but is actually malicious.
Mitigation: Code review system ensures that all reviews are informed and
meaningful.
Example: A proposed change updates a file, but the reviewer is only presented
with a diff of the cryptographic hash, not of the file contents. Thus, the
reviewer does not have enough context to provide a meaningful review. Solution:
the code review system should present the reviewer with a content diff or some
other information to make an informed decision.
Copy a reviewed change to another context
Threat: Get a change reviewed in one context and then transfer it to a
different context.
Mitigation: Approvals are context-specific.
Example: MyPackage’s source repository requires two-person review. Adversary
forks the repo, submits a change in the fork with review from a colluding
colleague (who is not trusted by MyPackage), then merges the change back into
the upstream repo. Solution: The merge should still require review, even though
the fork was reviewed.
Compromise another account
Threat: Compromise one or more trusted accounts and use those to submit and
review own changes.
Mitigation: Source control platform verifies two-factor authentication, which
increases the difficulty of compromising accounts.
Example: Trusted person uses a weak password on GitHub. Adversary guesses the
weak password, logs in, and pushes changes to a GitHub repo. Solution: Configure
GitHub organization to requires 2FA for all trusted persons. This would increase
the difficulty of using the compromised password to log in to GitHub.
Hide bad change behind good one
Threat: Request review for a series of two commits, X and Y, where X is bad
and Y is good. Reviewer thinks they are approving only the final Y state whereas
they are also implicitly approving X.
Mitigation: Only the version that is actually reviewed is the one that is
approved. Any intermediate revisions don’t count as being reviewed.
Example: Adversary sends a pull request containing malicious commit X and
benign commit Y that undoes X. In the pull request UI, reviewer only reviews and
approves “changes from all commits”, which is a delta from HEAD to Y; they don’t
see X. Adversary then builds from the malicious revision X. Solution:
Expectations do not accept this because the version X is not considered
reviewed.
(A3) Code review bypasses that are out of scope of SLSA
Software producer intentionally submits bad code
Threat: Software producer intentionally submits “bad” code, following all
proper processes.
Mitigation: Outside the scope of SLSA. Trust of the software producer is
an important but separate property from integrity.
Example: A popular extension author sells the rights to a new owner, who then
modifies the code to secretly mine bitcoin at the users’ expense. SLSA does not
protect against this, though if the extension were open source, regular auditing
may discourage this from happening.
Collude with another trusted person
Threat: Two trusted persons collude to author and approve a bad change.
Mitigation: Outside the scope of SLSA. We use “two trusted persons” as a
proxy for “intent of the software producer”.
Trick reviewer into approving bad code
Threat: Construct a change that looks benign but is actually malicious, a.k.a.
“bugdoor.”
Mitigation: Outside the scope of SLSA.
Reviewer blindly approves changes
Threat: Reviewer approves changes without actually reviewing, a.k.a. “rubber
stamping.”
Mitigation: Outside the scope of SLSA.
(B) Compromise source repo
An adversary introduces a change to the source control repository through an
administrative interface, or through a compromise of the underlying
infrastructure.
Project owner bypasses or disables controls
Threat: Trusted person with “admin” privileges in a repository submits “bad”
code bypassing existing controls.
Mitigation: All persons are subject to same controls, whether or not they have
administrator privileges. Disabling the controls requires two-person review (and
maybe notifies other trusted persons?)
Example 1: GitHub project owner pushes a change without review, even though
GitHub branch protection is enabled. Solution: Enable the “Include
Administrators” option for the branch protection.
Example 2: GitHub project owner disables “Include Administrators”, pushes a
change without review, then re-enables “Include Administrators”. This currently
has no solution on GitHub.
Platform admin abuses privileges
Threat: Platform administrator abuses their privileges to bypass controls or
to push a malicious version of the software.
Mitigation: TBD
Example 1: GitHostingService employee uses an internal tool to push changes to
the MyPackage source repo.
Example 2: GitHostingService employee uses an internal tool to push a
malicious version of the server to serve malicious versions of MyPackage sources
to a specific CI/CD client but the regular version to everyone else, in order to
hide tracks.
Example 3: GitHostingService employee uses an internal tool to push a
malicious version of the server that includes a backdoor allowing specific users
to bypass branch protections. Adversary then uses this backdoor to submit a
change to MyPackage without review.
Exploit vulnerability in SCM
Threat: Exploit a vulnerability in the implementation of the source code
management system to bypass controls.
Mitigation: Outside the scope of SLSA.
Build integrity threats
A build integrity threat is a potential for an adversary to introduce behavior
to a package that is not reflected in the source code, or to build from a
source, dependency, and/or process that is not intended by the software
producer.
The SLSA Build track covers these threats when combined with verifying artifacts
against expectations.
(C) Build from modified source
An adversary builds from a version of the source code that does not match the
official source control repository.
The mitigation here is to compare the provenance against expectations for the
package, which depends on SLSA Build L1 for provenance. (Threats against the
provenance itself are covered by (D) and (F).)
Build from unofficial fork of code (expectations)
Threat: Build using the expected CI/CD process but from an unofficial fork of
the code that may contain unauthorized changes.
Mitigation: Verifier requires the provenance’s source location to match an
expected value.
Example: MyPackage is supposed to be built from GitHub repo good/my-package
.
Instead, it is built from evilfork/my-package
. Solution: Verifier rejects
because the source location does not match.
Build from unofficial branch or tag (expectations)
Threat: Build using the expected CI/CD process and source location, but
checking out an “experimental” branch or similar that may contain code not
intended for release.
Mitigation: Verifier requires that the provenance’s source branch/tag matches
an expected value, or that the source revision is reachable from an expected
branch.
Example: MyPackage’s releases are tagged from the main
branch, which has
branch protections. Adversary builds from the unprotected experimental
branch
containing unofficial changes. Solution: Verifier rejects because the source
revision is not reachable from main
.
Build from unofficial build steps (expectations)
Threat: Build the package using the proper CI/CD platform but with unofficial
build steps.
Mitigation: Verifier requires that the provenance’s build configuration source
matches an expected value.
Example: MyPackage is expected to be built by Google Cloud Build using the
build steps defined in the source’s cloudbuild.yaml
file. Adversary builds
with Google Cloud Build, but using custom build steps provided over RPC.
Solution: Verifier rejects because the build steps did not come from the
expected source.
Build from unofficial parameters (expectations)
Threat: Build using the expected CI/CD process, source location, and
branch/tag, but using a parameter that injects unofficial behavior.
Mitigation: Verifier requires that the provenance’s external parameters all
match expected values.
Example 1: MyPackage is supposed to be built from the release.yml
workflow.
Adversary builds from the debug.yml
workflow. Solution: Verifier rejects
because the workflow parameter does not match the expected value.
Example 2: MyPackage’s GitHub Actions Workflow uses github.event.inputs
to
allow users to specify custom compiler flags per invocation. Adversary sets a
compiler flag that overrides a macro to inject malicious behavior into the
output binary. Solution: Verifier rejects because the inputs
parameter was not
expected.
Build from modified version of code modified after checkout (expectations)
Threat: Build from a version of the code that includes modifications after
checkout.
Mitigation: Build service pulls directly from the source repository and
accurately records the source location in provenance.
Example: Adversary fetches from MyPackage’s source repo, makes a local commit,
then requests a build from that local commit. Builder records the fact that it
did not pull from the official source repo. Solution: Verifier rejects because
the source repo does not match the expected value.
(D) Compromise build process
An adversary introduces an unauthorized change to a build output through
tampering of the build process; or introduces false information into the
provenance.
These threats are directly addressed by the SLSA Build track.
Compromise build environment of subsequent build (Build L3)
Threat: Perform a “bad” build that persists a change in the build environment,
then run a subsequent “good” build using that environment.
Mitigation: Builder ensures that each build environment is ephemeral, with
no way to persist changes between subsequent builds.
Example: Build service uses the same machine for subsequent builds. Adversary
first runs a build that replaces the make
binary with a malicious version,
then runs a subsequent build that otherwise would pass expectations. Solution:
Builder changes architecture to start each build with a clean machine image.
Compromise parallel build (Build L3)
Threat: Perform a “bad” build that alters the behavior of another “good” build
running in parallel.
Mitigation: Builds are isolated from one another, with no way for one to
affect the other.
Example: Build service runs all builds for project MyPackage on the same
machine as the same Linux user. Adversary starts a “bad” build that listens for
the “good” build and swaps out source files, then starts a “good” build that
would otherwise pass expectations. Solution: Builder changes architecture to
isolate each build in a separate VM or similar.
Steal cryptographic secrets (Build L3)
Threat: Use or exfiltrate the provenance signing key or some other
cryptographic secret that should only be available to the build service.
Mitigation: Builds are isolated from the trusted build service control
plane, and only the control plane has access to cryptographic
secrets.
Example: Provenance is signed on the build worker, which the adversary has
control over. Adversary uses a malicious process that generates false provenance
and signs it using the provenance signing key. Solution: Builder generates and
signs provenance in the trusted control plane; the worker has no access to the
key.
Set values of the provenance (Build L2-L3)
Threat: Generate false provenance and get the trusted control plane to sign
it.
Mitigation: At Build L2+, trusted control plane generates all
information that goes in the provenance, except (optionally) the output artifact
hash. At Build L3+, this is hardened to prevent compromise even
by determined adversaries.
Example 1 (Build L2): Provenance is generated on the build worker, which the
adversary has control over. Adversary uses a malicious process to get the build
service to claim that it was built from source repo good/my-package
when it
was really built from evil/my-package
. Solution: Builder generates and signs
the provenance in the trusted control plane; the worker reports the output
artifacts but otherwise has no influence over the provenance.
Example 2 (Build L3): Provenance is generated in the trusted control plane,
but workers can break out of the container to access the signing material.
Solution: Builder is hardened to provide strong isolation against tenant
projects.
Poison the build cache (Build L3)
Threat: Add a “bad” artifact to a build cache that is later picked up by a
“good” build process.
Mitigation: Build caches must be isolate between builds to prevent
such cache poisoning attacks.
Example: Build system uses a build cache across builds, keyed by the hash of
the source file. Adversary runs a malicious build that creates a “poisoned”
cache entry with a falsified key, meaning that the value wasn’t really produced
from that source. A subsequent build then picks up that poisoned cache entry.
Project owner (TBD)
TODO: similar to Source (do the same threats apply here?)
Platform admin (TBD)
TODO: similar to Source
(E) Use compromised dependency
TODO: What exactly is this about? Is it about compromising the build
process through a bad build tool, and/or is it about compromising the output
package through a bad library? Does it involve all upstream threats to the
dependency, or is it just about this particular use of the package (e.g.
tampering on input, or choosing a bad dependency)?
TODO: Fill this out to give more examples of threats from compromised
dependencies.
(F) Upload modified package
An adversary uploads a package not built from the proper build process.
Build with untrusted CI/CD (expectations)
Threat: Build using an unofficial CI/CD pipeline that does not build in the
correct way.
Mitigation: Verifier requires provenance showing that the builder matched an
expected value.
Example: MyPackage is expected to be built on Google Cloud Build, which is
trusted up to Build L3. Adversary builds on SomeOtherBuildService, which is only
trusted up to Build L2, and then exploits SomeOtherBuildService to inject bad
behavior. Solution: Verifier rejects because builder is not as expected.
Upload package without provenance (Build L1)
Threat: Upload a package without provenance.
Mitigation: Verifier requires provenance before accepting the package.
Example: Adversary uploads a malicious version of MyPackage to the package
repository without provenance. Solution: Verifier rejects because provenance is
missing.
Tamper with artifact after CI/CD (Build L1)
Threat: Take a good version of the package, modify it in some way, then
re-upload it using the original provenance.
Mitigation: Verifier checks that the provenance’s subject
matches the hash
of the package.
Example: Adversary performs a proper build, modifies the artifact, then
uploads the modified version of the package to the repository along with the
provenance. Solution: Verifier rejects because the hash of the artifact does not
match the subject
found within the provenance.
Tamper with provenance (Build L2)
Threat: Perform a build that would not pass expectations, then modify the
provenance to make the expectations checks pass.
Mitigation: Verifier only accepts provenance with a valid cryptographic
signature or equivalent proving that the provenance came from an
acceptable builder.
Example: MyPackage is expected to be built by GitHub Actions from the
good/my-package
repo. Adversary builds with GitHub Actions from the
evil/my-package
repo and then modifies the provenance so that the source looks
like it came from good/my-package
. Solution: Verifier rejects because the
cryptographic signature is no longer valid.
(G) Compromise package repo
An adversary modifies the package on the package repository using an
administrative interface or through a compromise of the infrastructure.
TODO: fill this out
(H) Use compromised package
An adversary modifies the package after it has left the package repository, or
tricks the user into using an unintended package.
Typosquatting
Threat: Register a package name that is similar looking to a popular package
and get users to use your malicious package instead of the benign one.
Mitigation: Mostly outside the scope of SLSA. That said, the requirement
to make the source available can be a mild deterrent, can aid investigation or
ad-hoc analysis, and can complement source-based typosquatting solutions.
Availability threats
An availability threat is a potential for an adversary to deny someone from
reading a source and its associated change history, or from building a package.
SLSA v1.0 does not address availability threats, though future versions might.
(A)(B) Delete the code
Threat: Perform a build from a particular source revision and then delete that
revision or cause it to get garbage collected, preventing anyone from inspecting
the code.
Mitigation: Some system retains the revision and its version control history,
making it available for inspection indefinitely. Users cannot delete the
revision except as part of a transparent legal or privacy process.
Example: Adversary submits bad code to the MyPackage GitHub repo, builds from
that revision, then does a force push to erase that revision from history (or
requests GitHub to delete the repo.) This would make the revision unavailable
for inspection. Solution: Verifier rejects the package because it lacks a
positive attestation showing that some system, such as GitHub, ensured retention
and availability of the source code.
(E) A dependency becomes temporarily or permanently unavailable to the build process
Threat: Unable to perform a build with the intended dependencies.
Mitigation: Outside the scope of SLSA. That said, some solutions to
support hermetic and reproducible builds may also reduce the impact of this
threat.
Other threats
Threats that can compromise the ability to prevent or detect the supply chain
security threats above but that do not fall cleanly into any one category.
Tamper with expectations
Threat: Modify the expectations to accept something that would not otherwise
be accepted.
Mitigation: Changes to expectations require some form of authorization, such
as two-party review.
Example: Expectations for MyPackage only allows source repo good/my-package
.
Adversary modifies the expectations to also accept evil/my-package
, then
builds from that repo and uploads a bad version of the package. Solution:
Expectation changes require two-party review.
Forge change metadata
Threat: Forge the change metadata to alter attribution, timestamp, or
discoverability of a change.
Mitigation: Source control platform strongly authenticates actor identity,
timestamp, and parent revisions.
Example: Adversary submits a git commit with a falsified author and timestamp,
and then rewrites history with a non-fast-forward update to make it appear to
have been made long ago. Solution: Consumer detects this by seeing that such
changes are not strongly authenticated and thus not trustworthy.
Exploit cryptographic hash collisions
Threat: Exploit a cryptographic hash collision weakness to bypass one of the
other controls.
Mitigation: Require cryptographically secure hash functions for code review
and provenance, such as SHA-256.
Examples: Construct a “good” file and a “bad” file with the same SHA-1 hash.
Get the “good” file reviewed and then submit the “bad” file, or get the “good”
file reviewed and submitted and then build from the “bad” file. Solution: Only
accept cryptographic hashes with strong collision resistance.
Frequently Asked Questions
Q: Why is SLSA not transitive?
SLSA Build levels only cover the trustworthiness of a single build, with no
requirements about the build levels of transitive dependencies. The reason for
this is to make the problem tractable. If a SLSA Build level required
dependencies to be the same level, then reaching a level would require starting
at the very beginning of the supply chain and working forward. This is
backwards, forcing us to work on the least risky component first and blocking
any progress further downstream. By making each artifact’s SLSA rating
independent from one another, it allows parallel progress and prioritization
based on risk. (This is a lesson we learned when deploying other security
controls at scale throughout Google.) We expect SLSA ratings to be composed to
describe a supply chain’s overall security stance, as described in the case
study vision.
Q: What about reproducible builds?
When talking about reproducible builds, there
are two related but distinct concepts: “reproducible” and “verified
reproducible.”
“Reproducible” means that repeating the build with the same inputs results in
bit-for-bit identical output. This property
provides
many
benefits,
including easier debugging, more confident cherry-pick releases, better build
caching and storage efficiency, and accurate dependency tracking.
“Verified reproducible” means using two or more independent build systems to
corroborate the provenance of a build. In this way, one can create an overall
system that is more trustworthy than any of the individual components. This is
often
suggested
as a solution to supply chain integrity. Indeed, this is one option to secure
build steps of a supply chain. When designed correctly, such a system can
satisfy all of the SLSA Build level requirements.
That said, verified reproducible builds are not a complete solution to supply
chain integrity, nor are they practical in all cases:
- Reproducible builds do not address source, dependency, or distribution
threats.
- Reproducers must truly be independent, lest they all be susceptible to the
same attack. For example, if all rebuilders run the same pipeline software,
and that software has a vulnerability that can be triggered by sending a
build request, then an attacker can compromise all rebuilders, violating the
assumption above.
- Some builds cannot easily be made reproducible, as noted above.
- Closed-source reproducible builds require the code owner to either grant
source access to multiple independent rebuilders, which is unacceptable in
many cases, or develop multiple, independent in-house rebuilders, which is
likely prohibitively expensive.
Therefore, SLSA does not require verified reproducible builds directly. Instead,
verified reproducible builds are one option for implementing the requirements.
For more on reproducibility, see
Hermetic, Reproducible, or Verifiable?
Q: How does SLSA relate to in-toto?
in-toto is a framework to secure software supply chains
hosted at the Cloud Native Computing Foundation. The in-toto
specification provides a generalized workflow to secure different steps in a
software supply chain. The SLSA specification recommends
in-toto attestations as the vehicle to
express Provenance and other attributes of software supply chains. Thus, in-toto
can be thought of as the unopinionated layer to express information pertaining
to a software supply chain, and SLSA as the opinionated layer specifying exactly
what information must be captured in in-toto metadata to achieve the guarantees
of a particular level.
in-toto’s official implementations written in
Go,
Java, and
Rust include support for generating
SLSA Provenance metadata. These APIs are used in other tools generating SLSA
Provenance such as Sigstore’s cosign, the SLSA GitHub Generator, and the in-toto
Jenkins plugin.
Future directions
The initial draft version (v0.1) of SLSA had a larger scope including
protections against tampering with source code and a higher level of build
integrity (Build L4). This section collects some early thoughts on how SLSA
might evolve in future version to re-introduce those notions and add other
additional aspects of automatable supply chain security.
Build track
Build L4
A build L4 could include further hardening of the build service and enabling
corraboration of the provenance, for example by providing complete knowledge of
the build inputs.
The initial draft version (v0.1) of SLSA defined a “SLSA 4” that included the
following requirements, which may or may not be part of a future Build L4:
- Pinned dependencies, which guarantee that each build runs on exactly the
same set of inputs.
- Hermetic builds, which guarantee that no extraneous dependencies are used.
- All dependencies listed in the provenance, which enables downstream systems
to recursively apply SLSA to dependencies.
- Reproducible builds, which enable other systems to corroborate the
provenance.
Source track
A Source track could provide protection against tampering of the source code
prior to the build.
The initial draft version (v0.1)
of SLSA included the following source requirements, which may or may not
form the basis for a future Source track:
- Strong authentication of author and reviewer identities, such as 2-factor
authentication using a hardware security key, to resist account and
credential compromise.
- Retention of the source code to allow for after-the-fact inspection and
future rebuilds.
- Mandatory two-person review of all changes to the source to prevent a single
compromised actor or account from introducing malicious changes.
Provenance
To trace software back to the source and define the moving parts in a complex
supply chain, provenance needs to be there from the very beginning. It’s the
verifiable information about software artifacts describing where, when and how
something was produced. For higher SLSA levels and more resilient integrity
guarantees, provenance requirements are stricter and need a deeper, more
technical understanding of the predicate.
This document defines the following predicate type within the in-toto
attestation framework:
"predicateType": "https://slsa.dev/provenance/v1-rc1"
Important: Always use the above string for predicateType
rather than what is
in the URL bar. The predicateType
URI will always resolve to the latest
minor version of this specification. See parsing rules for
more information.
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”,
“SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be
interpreted as described in RFC 2119.
Purpose
Describe how an artifact or set of artifacts was produced so that:
- Consumers of the provenance can verify that the artifact was built according
to expectations.
- Others can rebuild the artifact, if desired.
This predicate is the RECOMMENDED way to satisfy the SLSA v1.0 provenance
requirements.
Model
Provenance is an attestation that the builder
produced the subject
software
artifacts through execution of the buildDefinition
.
The model is as follows:
-
Each build runs as an independent process on a multi-tenant platform. The
builder.id
identifies this platform, representing the transitive
closure of all entities that are trusted to faithfully run the build and
record the provenance. (Note: The same model can be used for platform-less
or single-tenant build systems.)
-
The build process is defined by a parameterized template, identified by
buildType
. This encapsulates the process that ran, regardless of what
system ran it. Often the build type is specific to the build platform
because most build platforms have their own unique interfaces.
-
All top-level, independent inputs are captured by the parameters to the
template. There are two types of parameters:
-
externalParameters
: the external interface to the build. In SLSA,
these values are untrusted; they MUST be included in the provenance and
MUST be verified downstream.
-
systemParameters
: set internally by the platform. In SLSA, these
values are trusted because the platform is trusted; they are OPTIONAL
and need not be verified downstream. They MAY be included to enable
reproducible builds, debugging, or incident response.
-
All artifacts fetched during initialization or execution of the build
process are considered dependencies, including those referenced directly by
parameters. The resolvedDependencies
captures these dependencies, if
known. For example, a build that takes a git repository URI as a parameter
might record the specific git commit that the URI resolved to as a
dependency.
-
During execution, the build process might communicate with the build
platform’s control plane and/or build caches. This communication is not
captured directly in the provenance, but is instead implied by builder.id
and subject to SLSA Requirements. Such
communication SHOULD NOT influence the definition of the build; if it does,
it SHOULD go in resolvedDependencies
instead.
-
Finally, the build process outputs one or more artifacts, identified by
subject
.
For concrete examples, see index of build types.
Parsing rules
This predicate follows the in-toto attestation parsing rules. Summary:
- Consumers MUST ignore unrecognized fields unless otherwise noted.
- The
predicateType
URI includes the major version number and will always
change whenever there is a backwards incompatible change.
- Minor version changes are always backwards compatible and “monotonic.” Such
changes do not update the
predicateType
.
- Producers MAY add extension fields using field names that are URIs.
- Unset, null, and empty field values MUST be interpreted equivalently.
Schema
NOTE: This subsection describes the fields within predicate
. For a description
of the other top-level fields, such as subject
, see Statement.
{% include_relative schema/provenance.cue %}
Protocol buffer schema
Link: provenance.proto
{% include_relative schema/provenance.proto %}
Provenance
REQUIRED for SLSA Build L1: buildDefinition
, runDetails
Field | Type | Description
|
---|
buildDefinition
| BuildDefinition |
The input to the build. The accuracy and completeness are implied by
runDetails.builder.id .
|
runDetails
| RunDetails |
Details specific to this particular execution of the build.
|
BuildDefinition
REQUIRED for SLSA Build L1: buildType
, externalParameters
Field | Type | Description
|
---|
buildType
| string (TypeURI) |
Identifies the template for how to perform the build and interpret the
parameters and dependencies.
The URI SHOULD resolve to a human-readable specification that includes: overall
description of the build type; schema for externalParameters and
systemParameters ; unambiguous instructions for how to initiate the build given
this BuildDefinition, and a complete example. Example:
https://slsa-framework.github.io/github-actions-buildtypes/workflow/v1
|
externalParameters
| object |
The parameters that are under external control, such as those set by a user or
tenant of the build system. They MUST be complete at SLSA Build L3, meaning that
that there is no additional mechanism for an external party to influence the
build. (At lower SLSA Build levels, the completeness MAY be best effort.)
The build system SHOULD be designed to minimize the size and complexity of
externalParameters , in order to reduce fragility and ease verification.
Consumers SHOULD have an expectation of what “good” looks like; the more
information that they need to check, the harder that task becomes.
Verifiers SHOULD reject unrecognized or unexpected fields within
externalParameters .
|
systemParameters
| object |
The parameters that are under the control of the entity represented by
builder.id . The primary intention of this field is for debugging, incident
response, and vulnerability management. The values here MAY be necessary for
reproducing the build. There is no need to verify these
parameters because the build system is already trusted, and in many cases it is
not practical to do so.
NOTE: This field is named internalParameters in v1 final.
|
resolvedDependencies
| array (ArtifactReference) |
Unordered collection of artifacts needed at build time. Completeness is best
effort, at least through SLSA Build L3. For example, if the build script fetches
and executes “example.com/foo.sh”, which in turn fetches
“example.com/bar.tar.gz”, then both “foo.sh” and “bar.tar.gz” SHOULD be listed
here.
|
The BuildDefinition describes all of the inputs to the build. It SHOULD contain
all the information necessary and sufficient to initialize the build and begin
execution.
The externalParameters
and systemParameters
are the top-level inputs to the
template, meaning inputs not derived from another input. Each is an arbitrary
JSON object, though it is RECOMMENDED to keep the structure simple with string
values to aid verification. The same field name SHOULD NOT be used for both
externalParameters
and systemParameters
.
The parameters SHOULD only contain the actual values passed in through the
interface to the build system. Metadata about those parameter values,
particularly digests of artifacts referenced by those parameters, SHOULD instead
go in resolvedDependencies
. The documentation for buildType
SHOULD explain
how to convert from a parameter to the dependency uri
. For example:
"externalParameters": {
"repository": "https://github.com/octocat/hello-world",
"ref": "refs/heads/main"
},
"resolvedDependencies": [{
"uri": "git+https://github.com/octocat/hello-world@refs/heads/main",
"digest": {"sha1": "7fd1a60b01f91b314f59955a4e4d4e80d8edf11d"}
}]
Guidelines:
-
Maximize the amount of information that is implicit from the meaning of
buildType
. In particular, any value that is boilerplate and the same
for every build SHOULD be implicit.
-
Reduce parameters by moving configuration to input artifacts whenever
possible. For example, instead of passing in compiler flags via an external
parameter that has to be verified separately, require the
flags to live next to the source code or build configuration so that
verifying the latter automatically verifies the compiler flags.
-
In some cases, additional external parameters might exist that do not impact
the behavior of the build, such as a deadline or priority. These extra
parameters SHOULD be excluded from the provenance after careful analysis
that they indeed pose no security impact.
-
If possible, architect the build system to use this definition as its
sole top-level input, in order to guarantee that the information is
sufficient to run the build.
-
When build configuration is evaluated client-side before being sent to the
server, such as transforming version-controlled YAML into ephemeral JSON,
some solution is needed to make verification practical. Consumers need a
way to know what configuration is expected and the usual way to do that is
to map it back to version control, but that is not possible if the server
cannot verify the configuration’s origins. Possible solutions:
-
(RECOMMENDED) Rearchitect the build service to read configuration
directly from version control, recording the server-verified URI in
externalParameters
and the digest in resolvedDependencies
.
-
Record the digest in the provenance and use a separate
provenance attestation to link that digest back to version control. In
this solution, the client-side evaluation is considered a separate
“build” that SHOULD be independently secured using SLSA, though securing
it can be difficult since it usually runs on an untrusted workstation.
-
The purpose of resolvedDependencies
is to facilitate recursive analysis of
the software supply chain. Where practical, it is valuable to record the
URI and digest of artifacts that, if compromised, could impact the build. At
SLSA Build L3, completeness is considered “best effort”.
⚠ RFC: We are particularly looking for feedback on this schema from
potential implementers. Does this model map cleanly to existing build systems?
Is it natural to identify and express the external parameters? Is anything
confusing or ambiguous?
ArtifactReference
REQUIRED: at least one of uri
or digest
Field | Type | Description
|
---|
uri
| string (URI) |
URI describing where this artifact came from. When possible, this SHOULD
be a universal and stable identifier, such as a source location or Package
URL (purl).
|
digest
| DigestSet |
One or more cryptographic digests of the contents of this artifact.
|
localName
| string |
The name for this artifact local to the build.
|
downloadLocation
| string (URI) |
URI identifying the location that this artifact was downloaded from, if
different and not derivable from uri .
|
mediaType
| string (MediaType) |
Media type (aka MIME type) of this artifact was interpreted.
|
Example:
{
"uri": "pkg:pypi/pyyaml@6.0",
"digest": {"sha256": "5f0689d54944564971f2811f9788218bfafb21aa20f532e6490004377dfa648f"},
"localName": "PyYAML-6.0.tar.gz",
"downloadLocation": "https://files.pythonhosted.org/packages/36/2b/61d51a2c4f25ef062ae3f74576b01638bebad5e045f747ff12643df63844/PyYAML-6.0.tar.gz",
"mediaType": "application/gzip"
}
⚠ RFC: Do we need all these fields? Is this adding too much complexity?
RunDetails
REQUIRED for SLSA Build L1: builder
Field | Type | Description
|
---|
builder
| Builder |
Identifies the entity that executed the invocation, which is trusted to have
correctly performed the operation and populated this provenance.
|
metadata
| BuildMetadata |
Metadata about this particular execution of the build.
|
byproducts
| array (ArtifactReference) |
Additional artifacts generated during the build that are not considered
the “output” of the build but that might be needed during debugging or incident
response. For example, this might reference logs generated during the build
and/or a digest of the fully evaluated build configuration.
In most cases, this SHOULD NOT contain all intermediate files generated during
the build. Instead, this SHOULD only contain files that are likely to be useful
later and that cannot be easily reproduced.
|
Builder
REQUIRED for SLSA Build L1: id
Field | Type | Description
|
---|
id
| string (TypeURI) |
URI indicating the transitive closure of the trusted builder. This is
intended to be the sole determiner of the SLSA Build level.
If a build platform has multiple modes of operations that have differing
security attributes or SLSA Build levels, each mode MUST have a different
builder.id and SHOULD have a different signer identity. This is to minimize
the risk that a less secure mode compromises a more secure one.
|
version
| map (string→string) |
Version numbers of components of the builder.
|
builderDependencies
| array (ArtifactReference) |
Dependencies used by the orchestrator that are not run within the workload and
that do not affect the build, but might affect the provenance generation or
security guarantees.
|
The builder represents the transitive closure of all the entities that are, by
necessity, trusted to faithfully run the build and record the provenance.
The id
MUST reflect the trust base that consumers care about. How detailed to
be is a judgement call. For example, GitHub Actions supports both GitHub-hosted
runners and self-hosted runners. The GitHub-hosted runner might be a single
identity because it’s all GitHub from the consumer’s perspective. Meanwhile,
each self-hosted runner might have its own identity because not all runners are
trusted by all consumers.
Consumers MUST accept only specific signer-builder pairs. For example, “GitHub”
can sign provenance for the “GitHub Actions” builder, and “Google” can sign
provenance for the “Google Cloud Build” builder, but “GitHub” cannot sign for
the “Google Cloud Build” builder.
Design rationale: The builder is distinct from the signer in order to support
the case where one signer generates attestations for more than one builder, as
in the GitHub Actions example above. The field is REQUIRED, even if it is
implicit from the signer, to aid readability and debugging. It is an object to
allow additional fields in the future, in case one URI is not sufficient.
⚠ RFC: Do we need more explicit guidance on how to choose a URI?
⚠ RFC: Would it be preferable to allow builders to set arbitrary
properties, rather than calling out version
and builderDependencies
? We
don’t expect verifiers to use any of them, so maybe that’s the simpler
approach? Or have a properties
that is an arbitrary object? (#319)
⚠ RFC: Do we want/need to identify the tenant of the build system,
separately from the build system itself? If so, a single id
that combines both (e.g.
https://builder.example/tenants/company1.example/project1
) or two separate
fields (e.g. {"id": "https://builder.example", "tenant": "https://company1.example/project1"}
)? What would the use case be for this?
How does verification work?
REQUIRED: (none)
Field | Type | Description
|
---|
invocationId
| string |
Identifies this particular build invocation, which can be useful for finding
associated logs or other ad-hoc analysis. The exact meaning and format is
defined by builder.id ; by default it is treated as opaque and case-sensitive.
The value SHOULD be globally unique.
|
startedOn
| string (Timestamp) |
The timestamp of when the build started.
|
finishedOn
| string (Timestamp) |
The timestamp of when the build completed.
|
Verification
Verification of provenance encompasses the following steps.
Step 1: Check SLSA Build level
First, check the SLSA Build level by comparing the artifact to its provenance
and the provenance to a preconfigured root of trust. The goal is to ensure that
the provenance actually applies to the artifact in question and to assess the
trustworthiness of the provenance. This mitigates some or all of threats “D”,
“F”, “G”, and “H”, depending on SLSA Build level and where verification happens.
Up front:
-
Configure the verifier’s roots of trust, meaning the recognized builder
identities and the maximum SLSA Build level each builder is trusted up to.
Different verifiers might use different roots of trust, but usually a
verifier uses the same roots of trust for all packages. This is likely in
the form of a map from (builder public key identity, builder.id
) to
(SLSA Build level).
Example root of trust configuration
The following snippet shows conceptually how a verifier’s roots of trust
might be configured using made-up syntax.
"slsaRootsOfTrust": [
// A builder trusted at SLSA Build L3, using a fixed public key.
{
"publicKey": "HKJEwI...",
"builderId": "https://somebuilder.example.com/slsa/l3",
"slsaBuildLevel": 3
},
// A different builder that claims to be SLSA Build L3,
// but this verifier only trusts it to L2.
{
"publicKey": "tLykq9...",
"builderId": "https://differentbuilder.example.com/slsa/l3",
"slsaBuildLevel": 2
},
// A builder that uses Sigstore for authentication, without a builder.id
{
"sigstore": {
"root": "global", // identifies fulcio/rekor roots
"subjectAlternativeNamePattern": "https://github.com/slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@refs/tags/v*.*.*"
}
"builderId": "", // empty for this particular builder
"slsaBuildLevel": 3,
}
...
],
Given an artifact and its provenance:
- Verify the envelope’s signature using the roots of trust, resulting in a
list of recognized public keys (or equivalent).
- Verify that statement’s
subject
matches the digest of the artifact in
question.
- Verify that the
predicateType
is https://slsa.dev/provenance/v1-rc1
.
- Look up the SLSA Build Level in the roots of trust, using the recognized
public keys and the
builder.id
, defaulting to SLSA Build L1.
Resulting threat mitigation:
- Threat “D”: SLSA Build L3 requires protection against compromise of the
build process and provenance generation by an external adversary, such as
persistence between builds or theft of the provenance signing key. In other
words, SLSA Build L3 establishes that the provenance is accurate and
trustworthy, assuming you trust the build platform.
- IMPORTANT: SLSA Build L3 does not cover compromise of the build
platform itself, such as by a malicious insider. Instead, verifiers
SHOULD carefully consider which build platforms are added to the roots
of trust. For advice on establishing trust in build platforms, see
Verifying build systems.
- Threat “F”: SLSA Build L2 covers tampering of the artifact or provenance
after the build. This is accomplished by verifying the
subject
and
signature in the steps above.
- Threat “G”: Verification by the consumer or otherwise outside of the
package registry covers compromise of the registry itself. (Verifying within
the registry at publication time is also valuable, but does not cover Threat
“G” or “H”.)
- Threat “H”: Verification by the consumer covers compromise of the package
in transit. (Many ecosystems also address this threat using package
signatures or checksums.)
- NOTE: SLSA does not cover adversaries tricking a consumer to use an
unintended package, such as through typosquatting.
Step 2: Check expectations
Next, check that the package’s provenance meets expectations for that package in
order to mitigate threat “C”.
In our threat model, the adversary has ability to invoke a build and to publish
to the registry but not to write to the source repository, nor do they have
insider access to any trusted systems. Expectations MUST be sufficient to detect
or prevent this adversary from injecting unofficial behavior into the package.
Example threats in this category include building from an unofficial fork or
abusing a build parameter to modify the build. Usually expectations identify the
canonical source repository (which is the entry in externalParameters
) and any
other security-relevant external parameters.
The expectations SHOULD cover the following:
What |
Why |
Builder identity from Step 1 |
To prevent an adversary from building the correct code on an unintended system |
buildType |
To ensure that externalParameters are interpreted as intended |
externalParameters |
To prevent an adversary from injecting unofficial behavior |
Verifiers SHOULD reject unrecognized fields in externalParameters
to err on
the side of caution. It is acceptable to allow a parameter to have a range of
values (possibly any value) if it is known that any value in the range is safe.
Implementations need not special-case the buildType
if JSON comparisons are
sufficient.
Possible models for implementing expectation setting in package ecosystems (not
exhaustive):
-
Trust on first use: Accept the first version of the package as-is. On
each version update, compare the old provenance to the new provenance and
alert on any differences. This can be augmented by having rules about what
changes are benign, such as a parameter known to be safe or a heuristic
about safe git refs.
-
Explicit policy: Package producer defines the expectations for the
package and distributes it to the verifier; the verifier uses these
expectations after verifying their authenticity. In this model, there MUST
be some protection against an adversary unilaterally modifying the policy.
For example, this might involve two-party control over policy modifications,
or having consumers accept each policy change (another form of trust on
first use).
-
Immutable policy: Expectations for a package cannot change. In this
model, the package name is immutably bound to a source repository and all
other expectations are defined in the source repository. This is how go
works, for example, since the package name is the source repository
location.
TIP: Difficulty in setting meaningful expectations for externalParameters
can
be a sign that the buildType
’s level of abstraction is too low. For example,
externalParameters
that record a list of commands to run is likely impractical
to verify because the commands change on every build. Instead, consider a
buildType
that defines the list of commands in a configuration file in a
source repository, then make put only the source repository in
externalParameters
. Such a design is easier to verify because the source
repository is constant across builds.
Step 3: Check dependencies (recursively)
Finally, recursively check the resolvedDependencies
as available and to the
extent desired. This mitigates threat “E”. While SLSA v1.0 does not have any
requirements on the completeness or verification of resolvedDependencies
, one
might wish to go beyond SLSA’s minimum requirements in order to protect against
threats further up the supply chain.
One possible approach is to recursively verify each entry in
resolvedDependencies
. A Verification Summary Attestation (VSA) can make
this process more efficient by recording the result of prior verifications. A
trimming heuristic or exception mechanism will almost always be necessary
because there will always be some transitive dependencies that are SLSA Build
L0. (For example, consider the compiler’s compiler’s compiler’s … compiler.)
If resolvedDependencies
is incomplete, this can be done on a best-effort
basis.
Index of build types
The following is an partial index of build type definitions. Each contains a
complete example predicate.
TODO: Before marking the spec stable, add at least 1-2 other build types to
validate that the design is general enough to apply to other builders.
Migrating from 0.2
To migrate from version 0.2 (old
), use the following
pseudocode. The meaning of each field is unchanged unless otherwise noted.
{
"buildDefinition": {
// The `buildType` MUST be updated for v1.0 to describe how to
// interpret `inputArtifacts`.
"buildType": /* updated version of */ old.buildType,
"externalParameters":
old.invocation.parameters + {
// It is RECOMMENDED to rename "entryPoint" to something more
// descriptive.
"entryPoint": old.invocation.configSource.entryPoint,
// It is OPTIONAL to rename "source" to something more descriptive,
// especially if "source" is ambiguous or confusing.
"source": old.invocation.configSource.uri,
},
"systemParameters": old.invocation.environment,
"resolvedDependencies":
old.materials + [
{
"uri": old.invocation.configSource.uri,
"digest": old.invocation.configSource.digest,
}
]
},
"runDetails": {
"builder": {
"id": old.builder.id,
"version": null, // not in v0.2
"builderDependencies": null, // not in v0.2
},
"metadata": {
"invocationId": old.metadata.buildInvocationId,
"startedOn": old.metadata.buildStartedOn,
"finishedOn": old.metadata.buildFinishedOn,
},
"byproducts": null, // not in v0.2
},
}
The following fields from v0.2 are no longer present in v1.0:
entryPoint
: Use externalParameters[<name>]
instead.
buildConfig
: No longer inlined into the provenance. Instead, either:
- If the configuration is a top-level input, record its digest in
externalParameters["config"]
.
- Else if there is a known use case for knowing the exact resolved
build configuration, record its digest in
byproducts
. An example use
case might be someone who wishes to parse the configuration to look for
bad patterns, such as curl | bash
.
- Else omit it.
metadata.completeness
: Now implicit from builder.id
.
metadata.reproducible
: Now implicit from builder.id
.
Change history
v1.0 RC1
Major refactor to reduce misinterpretation, including a minor change in model.
- Significantly expanded all documentation.
- Altered the model slightly to better align with real-world build systems,
align with reproducible builds, and make verification easier.
- Grouped fields into
buildDefinition
vs runDetails
.
- Renamed, with slight changes in semantics:
parameters
-> externalParameters
environment
-> systemParameters
materials
-> resolvedDependencies
- Removed:
configSource
: No longer special-cased. Now represented as
externalParameters
+ resolvedDependencies
.
buildConfig
: No longer inlined into the provenance. Can be replaced
with a reference in externalParameters
or byproducts
, depending on
the semantics, or omitted if not needed.
completeness
and reproducible
: Now implied by builder.id
.
- Added:
localName
, downloadLocation
, and mediaType
builder.version
byproducts
v0.2
Refactored to aid clarity and added buildConfig
. The model is unchanged.
- Replaced
definedInMaterial
and entryPoint
with configSource
.
- Renamed
recipe
to invocation
.
- Moved
invocation.type
to top-level buildType
.
- Renamed
arguments
to parameters
.
- Added
buildConfig
, which can be used as an alternative to configSource
to validate the configuration.
rename: slsa.dev/provenance
Renamed to “slsa.dev/provenance”.
v0.1.1
- Added
metadata.buildInvocationId
.
v0.1
Initial version, named “in-toto.io/Provenance”