Pinned Dependencies
ID |
openssf_scorecard/pinned_dependencies |
Severity |
high |
Category |
|
Levels |
|
Optional |
false |
Tags |
dependencies, security, slsa-4, supply-chain |
Description
Does the project declare and pin dependencies?
This check tries to determine if the project pins its dependencies. A pinned dependency is a dependency that is explicitly set to a specific one instead of allowing a mutable version or range of versions.
Reference: OpenSSF Scorecard - Pinned Dependencies.
Rationale
Pinned dependencies reduce several security risks:
-
They ensure that checking and deployment are all done with the same software, reducing deployment risks, simplifying debugging, and enabling reproducibility.
-
They can help mitigate compromised dependencies from undermining the security of the project (in the case where you’ve evaluated the pinned dependency, you are confident it’s not compromised, and a later version is released that is compromised).
-
They are one way to counter dependency confusion (aka substitution) attacks, in which an application uses multiple feeds to acquire software packages (a "hybrid configuration"), and attackers fool the user into using a malicious package via a feed that was not expected for that package.
However, pinning dependencies can inhibit software updates, either because of a security vulnerability or because the pinned version is compromised.
Mitigate this risk by:
-
having applications and not libraries pin to specific versions, as described here;
-
using automated tools to notify applications when their dependencies are outdated;
-
quickly updating applications that do pin dependencies.
Remediation
-
First determine if your project is producing a library or application. If it is a library, you generally don’t want to pin dependencies of library users, and should not follow any remediation steps.
-
If your project is producing an application, declare all your dependencies with specific versions in your package format file (e.g.
package.json
for npm,requirements.txt
for python). For C/C++, check in the code from a trusted source and add aREADME
on the specific version used (and the archive SHA hashes). -
If the package manager supports lock files (e.g.
package-lock.json
for npm), make sure to check these in the source code as well. These files maintain signatures for the entire dependency tree and saves from future exploitation in case a package is compromised. -
For Dockerfiles, pin dependencies by hash. See dockerfile for example. If you are using a manifest list to support builds across multiple architectures, you can pin to the manifest list hash instead of a single image hash. You can use a tool like crane to obtain the hash of the manifest list like in this example.
-
For GitHub workflows, pin dependencies by hash. See main.yaml for example. To determine the permissions needed for your workflows, you may use StepSecurity’s online tool by ticking the "Pin actions to a full length commit SHA". You may also tick the "Restrict permissions for GITHUB_TOKEN" to fix issues found by the Token-Permissions check.
-
To help update your dependencies after pinning them, use tools such as dependabot or renovatebot.