Basic security steps
Level 1 means the supply chain is documented, there’s infrastructure to generate provenance, and systems are prepared for higher SLSA levels.
SLSA is a set of standards and technical controls you can adopt to improve artifact integrity, and build towards completely resilient systems. It’s not a single tool, but a step-by-step outline to prevent artifacts being tampered with and tampered artifacts from being used, and at the higher levels, hardening up the platforms that make up a supply chain. These requirements are explained below, along with the rest of the essential specifications.
Protecting against key threats
Supply chain attacks are an ever-present threat, exploiting weakpoints to interfere with software. The SLSA framework establishes three trust boundaries encouraging the right standards, attestation and technical controls, so you can harden a system from these threats and risks.
This means automatic capability to analyse artifacts, guarantee the original source code, protect against interference that can happen in the build and distribution processes, isolate any hidden vulnerabilities and knowing with certainty which system components might be affected.
Real world examples
High profile attacks like SolarWinds, Codecov or Linux hypocrite commits exploit the kind of supply chain integrity vulnerabilities which may go unnoticed or be underdeveloped, and quickly become extremely public, disruptive and costly in today’s environment.
Attacks can occur at every link in a typical software supply chain, which puts an extra burden on anyone involved in complex critical systems. SLSA's designed with these examples in mind to make sure they’re common knowledge, and easier to protect against.
How it fits into the security ecosystem
There’s more to security than just protection against tampering. From vulnerability management and fuzzing to testing and developer trust, many of these require solutions where effort’s focused on the source. That’s where SLSA complements your wider security efforts, giving you confidence that the code you run is the code you analyzed.
SLSA’s requirements look at the three general main areas involved in a software artifact’s creation, and where vulnerabilities target - the build, the source, and the dependencies. As the levels scale up, they show that work’s been done to assure there’s more integrity in each area, which can be helpful in scenario planning.
SLSA starts at the build, the last step before an artifact’s released. This makes sure software’s built from the correct sources and dependencies, and hasn’t been modified. More resilient build integrity means protection from modifying code after source control, compromised build platforms or bypassing CI/CD.
Requirements can then focus on the source. All source code should reflect the intent of the software producer, that code and change history stay available for investigation. More resilient source integrity means better protection from bad code submitted without review or compromised source control systems.
Any other software artifacts fetched during the build process. Once the earlier security checks have been put into place, applying SLSA checks recursively to any dependencies in the system can then be followed up, which helps protect potentially massive attack surfaces against dependency confusion attacks.
Basic security steps
Level 1 means the supply chain is documented, there’s infrastructure to generate provenance, and systems are prepared for higher SLSA levels.
After the build
Level 2 shows more trustworthiness in the build, builders are source-aware, and signatures are used to prevent provenance being tampered with.
Back to source
Level 3 shows that a system’s builds are fully trustworthy, build definitions come from the source and a system has more hardened CI.
Across the chain
Level 4 means the build environment is fully accounted for, dependencies are tracked in provenance and insider threats are ruled out.
Before diving into the SLSA Levels, we need to establish a core set of terminology and models to describe what we’re protecting.
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.
|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.|
|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).|
We model a build as running on a multi-tenant platform, where each execution is independent. A tenant defines the build, including the input source artifact and the steps to execute. In response to an external trigger, the platform runs the build by initializing the environment, fetching the source and possibly some dependencies, and then starting execution inside the environment. The build then performs arbitrary steps, possibly fetching additional dependencies, and outputs one or more artifacts.
|Platform||System that allows tenants to run build. Technically, it is the transitive closure of software and services that must be trusted to faithfully execute the build.|
|Service||A platform that is hosted, not a developer’s machine. (Term used in requirements.)|
|Build||Process that converts input sources and dependencies into output artifacts, defined by the tenant and executed within a single environment.|
|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.|
|Trigger||External event or request causing the platform to run the build.|
|Source||Top-level input artifact required by the build.|
|Dependencies||Additional input artifacts required by the build.|
|Outputs||Collection of artifacts produced by the build.|
|Admin||Person with administrative access to the platform, potentially allowing them to tamper with the build process or access secret material.|
|Platform||GitHub Actions + runner + runner’s dependent services|
|Build||Workflow or job (either would be OK)|
|Source||git commit defining the workflow|
|Dependencies||any other artifacts fetched during execution|
Suppose a Bazel build runs on GitHub Actions using Bazel’s remote execution
feature. Some steps (namely
bazel itself) run on a GitHub Actions runner while
other steps (Bazel actions) run on a remote execution service.
In this case, the build’s environment is the union of the GitHub Actions runner environment plus the remote execution environment.
The model can still work for the case of a developer building on their local workstation, though this does not meet SLSA 2+.
|Build||whatever they ran|
|Steps||whatever they ran|
|Trigger||commands that the developer ran|
SLSA is organized into a series of levels that provide increasing integrity 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.
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 four levels are designed to be incremental and actionable, and to protect against specific integrity attacks. SLSA 4 represents the ideal end state, and the lower levels represent milestones with corresponding integrity guarantees.
|1||Documentation of the build process||Unsigned provenance|
|2||Tamper resistance of the build service||Hosted source/build, signed provenance|
|3||Extra resistance to specific threats||Security controls on host, non-falsifiable provenance|
|4||Highest levels of confidence and trust||Two-party review + hermetic builds|
It can take years to achieve the ideal security state - intermediate milestones are important. SLSA guides you through gradually improving the security of your software. Artifacts used in critical infrastructure or vital business operations may want to attain a higher level of security, whereas software that poses a low risk can stop when they’re comfortable.
|0||No guarantees. SLSA 0 represents the lack of any SLSA level.|
|1||The build process must be fully scripted/automated and generate provenance. Provenance is metadata about how an artifact was built, including the build process, top-level source, and dependencies. Knowing the provenance allows software consumers to make risk-based security decisions. Provenance at SLSA 1 does not protect against tampering, but it offers a basic level of code source identification and can aid in vulnerability management.|
|2||Requires using version control and a hosted build service that generates authenticated provenance. These additional requirements give the software consumer greater confidence in the origin of the software. At this level, the provenance prevents tampering to the extent that the build service is trusted. SLSA 2 also provides an easy upgrade path to SLSA 3.|
|3||The source and build platforms meet specific standards to guarantee the auditability of the source and the integrity of the provenance respectively. We envision an accreditation process whereby auditors certify that platforms meet the requirements, which consumers can then rely on. SLSA 3 provides much stronger protections against tampering than earlier levels by preventing specific classes of threats, such as cross-build contamination.|
|4||Requires two-person review of all changes and a hermetic, reproducible build process. Two-person review is an industry best practice for catching mistakes and deterring bad behavior. Hermetic builds guarantee that the provenance’s list of dependencies is complete. Reproducible builds, though not strictly required, provide many auditability and reliability benefits. Overall, SLSA 4 gives the consumer a high degree of confidence that the software has not been tampered with.|
The SLSA level is not transitive (see our FAQs). This makes each artifact’s SLSA rating independent from one another, allowing parallel progress and prioritization based on risk. The level describes the integrity protections of an artifact’s build process and top-level source, but nothing about the artifact’s dependencies. Dependencies have their own SLSA ratings, and it is possible for a SLSA 4 artifact to be built from SLSA 0 dependencies.
SLSA can help reduce supply chain threats in a software artifact, but there are limitations.
As part of our roadmap, we’ll explore how to identify important components, how to determine aggregate risk throughout a supply chain, and the role of accreditation.
This section covers all of the technical requirements for an artifact to meet the SLSA Levels.
Reminder: SLSA is in
alpha. The definitions below are not yet finalized and subject to change, particularly SLSA 3-4.
|Requirement||SLSA 1||SLSA 2||SLSA 3||SLSA 4|
|Source - Version controlled||✓||✓||✓|
|Source - Verified history||✓||✓|
|Source - Retained indefinitely||18 mo.||✓|
|Source - Two-person reviewed||✓|
|Build - Scripted build||✓||✓||✓||✓|
|Build - Build service||✓||✓||✓|
|Build - Build as code||✓||✓|
|Build - Ephemeral environment||✓||✓|
|Build - Isolated||✓||✓|
|Build - Parameterless||✓|
|Build - Hermetic||✓|
|Build - Reproducible||○|
|Provenance - Available||✓||✓||✓||✓|
|Provenance - Authenticated||✓||✓||✓|
|Provenance - Service generated||✓||✓||✓|
|Provenance - Non-falsifiable||✓||✓|
|Provenance - Dependencies complete||✓|
|Common - Security||✓|
|Common - Access||✓|
|Common - Superusers||✓|
○ = REQUIRED unless there is a justification
See also Terminology for general SLSA concepts. The defintions below are only used in this document.
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.
Immutable reference: An identifier that is guaranteed to always point to the same, immutable artifact. This MUST allow the consumer to locate the artifact and SHOULD include a cryptographic hash of the artifact’s contents to ensure integrity. Examples: git URL + branch/tag/ref + commit ID; cloud storage bucket ID + SHA-256 hash; Subversion URL (no hash).
Provenance: Metadata about how an artifact was produced.
Revision: An immutable, coherent state of a source. In Git, for example, a revision is a commit in the history reachable from a specific branch in a specific repository. Different revisions within one repo MAY have different levels. Example: the most recent revision on a branch meets SLSA 4 but very old historical revisions before the cutoff do not.
Strong authentication: Authentication that maps back to a specific person using an authentication mechanism which is resistant to account and credential compromise. For example, 2-factor authentication (2FA) where one factor is a hardware security key (i.e. YubiKey).
Trusted persons: Set of persons who are granted the authority to maintain a software project. For example, https://github.com/MarkLodato/dotfiles has just one trusted person (MarkLodato), while https://hg.mozilla.org/mozilla-central has a set of trusted persons with write access to the mozilla-central repository.
Every change to the source is tracked in a version control system that meets the following requirements:
Most popular version control system meet this requirement, such as git, Mercurial, Subversion, or Perforce.
NOTE: This does NOT require that the code, uploader/reviewer identities, or change history be made public. Rather, some organization MUST attest to the fact that these requirements are met, and it is up to the consumer whether this attestation is sufficient.
“○” = RECOMMENDED.
Every change in the revision’s history has at least one strongly authenticated actor identity (author, uploader, reviewer, etc.) and timestamp. It MUST be clear which identities were verified, and those identities MUST use two-step verification or similar. (Exceptions noted below.)
The revision and its change history are preserved indefinitely and cannot be deleted, except when subject to an established and transparent policy for obliteration, such as a legal or policy requirement.
Every change in the revision’s history was agreed to by two trusted persons prior to submission, and both of these trusted persons were strongly authenticated. (Exceptions from Verified History apply here as well.)
Requirements on build process:
All build steps were fully defined in some sort of “build script”. The only manual command, if any, was to invoke the build script.
All build steps ran using some build service, not on a developer’s workstation.
Examples: GitHub Actions, Google Cloud Build, Travis CI.
|Build as code||
The build definition and configuration executed by the build service is verifiably derived from text file definitions stored in a version control system.
Verifiably derived can mean either fetched directly through a trusted channel, or that the derived definition has some trustworthy provenance chain linking back to version control.
The build service ensured that the build steps ran in an ephemeral environment, such as a container or VM, provisioned solely for this build, and not reused from a prior build.
The build service ensured that the build steps ran in an isolated environment free of influence from other build instances, whether prior or concurrent.
The build output cannot be affected by user parameters other than the build entry point and the top-level source location. In other words, the build is fully defined through the build script and nothing else.
All transitive build steps, sources, and dependencies were fully declared up front with immutable references, and the build steps ran with no network access.
The user-defined build script:
The build service:
Re-running the build steps with identical input artifacts results in bit-for-bit identical output. Builds that cannot meet this MUST provide a justification why the build cannot be made reproducible.
“○” means that this requirement is “best effort”. The user-provided build script SHOULD declare whether the build is intended to be reproducible or a justification why not. The build service MAY blindly propagate this intent without verifying reproducibility. A consumer MAY reject the build if it does not reproduce.
Requirements on the process by which provenance is generated and consumed:
The provenance is available to the consumer in a format that the consumer accepts. The format SHOULD be in-toto SLSA Provenance, but another format MAY be used if both producer and consumer agree and it meets all the other requirements.
The provenance’s authenticity and integrity can be verified by the consumer. This SHOULD be through a digital signature from a private key accessible only to the service generating the provenance.
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).
Regular users of the service MUST NOT be able to inject or alter the contents, except as noted below.
The following provenance fields MAY be generated by the user-controlled build steps:
Provenance cannot be falsified by the build service’s users.
NOTE: This requirement is a stricter version of Service Generated.
The following provenance fields MAY be generated by the user-controlled build steps without the build service verifying their correctness:
Provenance records all build dependencies that were available while running the build steps. This includes the initial state of the machine, VM, or container of the build worker.
Requirements on the contents of the provenance:
The provenance MUST identify the output artifact via at least one cryptographic hash. The provenance MAY provide multiple identifying cryptographic hashes using different algorithms. When only one hash is provided, the RECOMMENDED algorithm is SHA-256 for cross-system compatibility. If another algorithm is used, it SHOULD be resistant to collisions and second preimages.
The provenance identifies the entity that performed the build and generated the
provenance. This represents the entity that the consumer MUST trust. Examples:
“GitHub Actions with a GitHub-hosted worker”, “
|Identifies build instructions||
The provenance identifies the top-level instructions used to execute the build.
The identified instructions SHOULD be at the highest level available to the build (e.g. if the build is told to run build.sh it SHOULD list build.sh and NOT the individual instructions in build.sh).
|Identifies source code||
The provenance identifies the repository origin(s) for the source code used in the build.
The identified repositories SHOULD only include source used directly in the build. The source of dependencies SHOULD NOT be included.
At level 2 this information MAY come from users and DOES NOT need to be authenticated by the builder.
At level 3+ this information MUST be authenticated by the builder (i.e. the builder either needs to have fetched the source itself or observed the fetch).
At level 4 this information MUST be complete (i.e. all source repositories used in the build are listed).
|✓||✓ (Authenticated)||✓ (Complete)|
|Identifies entry point||
The provenance identifies the “entry point” of the build definition (see build-as-code) used to drive the build including what source repo the configuration was read from.
|Includes all build parameters||
The provenance includes all build parameters under a user’s control. See Parameterless for details. (At L3, the parameters MUST be listed; at L4, they MUST be empty.)
|Includes all transitive dependencies||
The provenance includes all transitive dependencies listed in Dependencies Complete.
|Includes reproducible info||
The provenance includes a boolean indicating whether build is intended to be reproducible and, if so, all information necessary to reproduce the build. See Reproducible for more details.
The provenance includes metadata to aid debugging and investigations. This SHOULD at least include start and end timestamps and a unique identifier to allow finding detailed debug logs.
“○” = RECOMMENDED.
Common requirements for every trusted system involved in the supply chain (source, build, distribution, etc.)
The system meets some TBD baseline security standard to prevent compromise. (Patching, vulnerability scanning, user isolation, transport security, secure boot, machine identity, etc. Perhaps NIST 800-53 or a subset thereof.)
All physical and remote access MUST be rare, logged, and gated behind multi-party approval.
Only a small number of platform admins MAY override the guarantees listed here. Doing so MUST require approval of a second platform admin.
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 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.
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.
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:
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.
An adversary introduces a change through the official source control management interface without any special administrator privileges.
Threat: Submit bad code to the source repository without another person reviewing.
Mitigation: Source repository requires two-person approval for all changes. [Two-person reviewed @ SLSA 4]
Example: Adversary directly pushes a change to a GitHub repo’s
Solution: Configure GitHub’s “branch protection” feature to require pull request
reviews on the
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. [Two-person reviewed → Different persons @ SLSA 4]
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.
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. [Two-person reviewed @ SLSA 4]
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.
TODO(#196) This solution may not be practical. Should there be an exception for locked down robot accounts?
Threat: Exploit a review exception to submit a bad change without review.
Mitigation: All changes require two-person review without exception. [Two-person reviewed @ SLSA 4]
Example: Source repository requires two-person review on all changes except
for “documentation changes,” defined as only touching files ending with
.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 the policy because the source repository is correct,
and the source repository does require two-person review. Solution: Do not allow
TODO This solution may not be practical in all circumstances. Are there any valid exceptions? If so, how do we ensure they cannot be exploited?
Threat: Modify the code after it has been reviewed but before submission.
Mitigation: Source control platform invalidates approvals whenever the proposed change is modified. [NOT REQUIRED FOR SLSA]
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.
Note: This is not currently a SLSA requirement because the productivity hit is considered too great to outweigh the security benefit. The cost of code review is already too high for most projects, given current code review tooling, so making code review even costlier would not further our goals. However, this should be considered for future SLSA revisions once the state-of-the-art for code review has improved and the cost can be minimized.
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. [Two-person reviewed → Informed review @ SLSA 4]
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.
Threat: Get a change reviewed in one context and then transfer it to a different context.
Mitigation: Approvals are context-specific. [Two-person reviewed -> Context-specific approvals @ SLSA 4]
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.
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. [Verified history → strong authentication @ SLSA 3]
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.
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. [Two-person reviewed @ SLSA 4]
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: Policy does not accept this because the version X is not considered reviewed.
TODO This is implicit but not clearly spelled out in the requirements. We should consider clarifying if there is confusion or incorrect implementations.
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.
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”.
Threat: Construct a change that looks benign but is actually malicious, a.k.a. “bugdoor.”
Mitigation: Outside the scope of SLSA.
Threat: Reviewer approves changes without actually reviewing, a.k.a. “rubber stamping.”
Mitigation: Outside the scope of SLSA.
An adversary introduces a change to the source control repository through an administrative interface, or through a compromise of the underlying infrastructure.
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?) [Two-person reviewed @ SLSA 4]
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.
TODO This is implicit but not clearly spelled out in the requirements. We should consider clarifying since most if not all existing platforms do not properly address this threat.
Threat: Platform administrator abuses their privileges to bypass controls or to push a malicious version of the software.
Mitigation: TBD [Common requirements @ SLSA 4]
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.
Threat: Exploit a vulnerability in the implementation of the source code management system to bypass controls.
Mitigation: Outside the scope of SLSA.
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.
An adversary builds from a version of the source code that does not match the official source control repository.
Threat: Build using the expected CI/CD process but from an unofficial fork of the code that may contain unauthorized changes.
Mitigation: Policy requires the provenance’s source location to match an expected value.
Example: MyPackage is supposed to be built from GitHub repo
Instead, it is built from
evilfork/my-package. Solution: Policy rejects
because the source location does not match.
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: Policy 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
containing unofficial changes. Solution: Policy rejects because the source
revision is not reachable from
Threat: Build the package using the proper CI/CD platform but with unofficial build steps.
Mitigation: Policy 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: Policy rejects because the build steps did not come from the expected
Threat: Build using the expected CI/CD process, source location, and branch/tag, but using a target or entry point that is not intended for release.
Mitigation: Policy requires that the provenance’s build entry point matches an expected value.
Example: MyPackage is supposed to be built from the
Adversary builds from the
debug workflow. Solution: Policy rejects because the
entry point does not match.
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. [Identifies source code @ SLSA 3]
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: Policy rejects because the source repo is not as expected.
An adversary introduces an unauthorized change to a build output through tampering of the build process; or introduces false information into the provenance.
Threat: Build using the expected CI/CD process, source location, branch/tag, and entry point, but adding a build parameter that injects bad behavior into the output.
Mitigation: Policy only allows known-safe parameters. At SLSA 4, no parameters are allowed. [Parameterless @ SLSA 4]
Example: MyPackage’s GitHub Actions Workflow uses
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: Policy rejects because it does not allow any
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. [Ephemeral environment @ SLSA 3]
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 the policy. Solution:
Builder changes architecture to start each build with a clean machine image.
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. [Isolated @ SLSA 3]
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 the policy. Solution: Builder changes architecture to isolate each build in a separate VM or similar.
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. [Isolated @ SLSA 3]
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.
Threat: Generate false provenance and get the trusted control plane to sign it.
Mitigation: Trusted control plane generates all information that goes in the provenance, except (optionally) the output artifact hash. [Service generated @ SLSA 2]
Example: 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
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.
Threat: Add a “bad” artifact to a build cache that is later picked up by a “good” build process.
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.
TODO: similar to Source (do the same threats apply here?)
TODO: similar to Source
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.
An adversary uploads a package not built from the proper build process.
Threat: Build using an unofficial CI/CD pipeline that does not build in the correct way.
Mitigation: Policy 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 SLSA 4. Adversary builds on SomeOtherBuildService, which is only trusted up to SLSA 2, and then exploits SomeOtherBuildService to inject bad behavior. Solution: Policy rejects because builder is not as expected.
Threat: Upload a package without provenance.
Mitigation: Policy requires provenance showing that the package came from the expected CI/CD pipeline.
Example: Adversary uploads a malicious version of MyPackage to the package repository without provenance. Solution: Policy rejects because provenance is missing.
Threat: Take a good version of the package, modify it in some way, then re-upload it using the original provenance.
Mitigation: Policy requires provenance with a
subject matching the hash of
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: Policy rejects because the hash of the artifact does not
subject found within the provenance.
Threat: Perform a build that would not otherwise pass the policy, then modify the provenance to make the policy checks pass.
Mitigation: Policy only accepts provenance that was cryptographically signed by the public key corresponding to 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: Policy rejects because the
cryptographic signature is no longer valid.
An adversary modifies the package on the package repository using an administrative interface or through a compromise of the infrastructure.
TODO: fill this out
An adversary modifies the package after it has left the package repository, or tricks the user into using an unintended package.
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. [Verified history and Retained indefinitely @ SLSA 3]
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.
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. [Retained indefinitely @ SLSA 3-4]
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: Policy prevents this by requiring a positive attestation showing that some system, such as GitHub, ensures retention and availability.
Threat: Unable to perform a build with the intended dependencies.
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.
Threat: Modify the policy to accept something that would not otherwise be accepted.
Mitigation: Policies themselves must meet SLSA 4, including two-party review.
Example: Policy for MyPackage only allows source repo
Adversary modifies the policy to also accept
evil/my-package, then builds from
that repo and uploads a bad version of the package. Solution: Policy changes
require two-party review.
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. [Verified history @ SLSA 3]
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.
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.
SLSA is not transitive in order to make the problem tractable. If SLSA 4 required dependencies to be SLSA 4, then reaching SLSA 4 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.
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.
For these reasons, SLSA 4 requires reproducible builds unless there is a justification why the build cannot be made reproducible. Example justifications include profile-guided optimizations or code signing that invalidates hashes. Note that there is no actual reproduction, just a claim that reproduction is possible.
“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 requirements.
That said, verified reproducible builds are not a complete solution to supply chain integrity, nor are they practical in all cases:
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?
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.