By Yann Albou.
After explaining the principles of Supply Chain Attacks and how to list dependencies to track vulnerabilities through the SBOM, we will focus on updating dependencies.
This article is part of a series: “How to protect yourself from a “Supply Chain Attack””?
Updating your dependencies, packages and images is a necessary task, but for what purpose? who should be concerned about it and above all how to go about it?
As explained in the article La Supply Chain Attack? and in order to facilitate the implementation in accordance with our recommendations, we have adopted signage. Here is the one concerning our subject:
The scope concerns the Dev and CI (Continuous Integration) part. It is a practice to implement that requires moderate effort. This recommendation offers probability-type risk mitigation to reduce its possibility of occurring.
When designing a new application or Docker image, the actions of choosing versions of libraries, dependencies, packages, and base images are often performed quite early in the project lifecycle and are then rarely questioned except during key moments of these projects.
Why consider updates if the project already works without problems with current versions? In fact, there are several important reasons to do this:
In terms of security, the Open Worldwide Application Security Project (OWASP) Top 10 provides several rankings of the 10 most critical risks and vulnerabilities in different areas. We find, for example, vulnerable and obsolete components: A06 – Vulnerable and Outdated Components or dependency problems in CI/CD: CICD -SEC-3: Dependency Chain Abuse.
These OWASP categories highlight the fact that many applications use third-party components to speed development, but do not update them regularly or monitor for known vulnerabilities in those components.
The OWASP Top 10 therefore highlights the importance of managing software components in the context of application security.
Staying constantly up to date can be a challenge, but all of these improvements help ensure code maintainability and the robustness of your application.
Doing this very regularly avoids major big-bang changes in favor of more targeted updates.
Additionally, in case of critical vulnerabilities or important security patches, you should update dependencies immediately. The security of your application should always be a priority.
Keeping your system and its dependencies up to date is therefore essential for the security and maintainability of your applications.
Keeping a project’s tools and packages up to date can be difficult. This may cause problems (breaking changes) in the operation of the application.
Plus, it takes time and testing to make sure everything is working properly.
Many teams choose to only update when it is really necessary, which is a local optimization at a given time, but which will lead to bigger problems in the future, or even very harmful impacts on maintenance and security of applications.
Still, it’s important to keep things up to date because it improves security, makes developers more comfortable, and helps you stay on top of what’s new. Regular updates are easier to manage than big changes after long periods of time without an update.
This is the eternal question of technical debt: when should you make this effort?
As explained in the article on Supply Chain Attack? the attack vectors are multiplying, and it is no longer an option to update very regularly!
It therefore becomes important to increase its capacity to deploy, but be careful not to saturate this change capacity solely for updating dependencies.
The responsibility for doing these update actions may vary depending on the structure of your team, the size of your project and how you manage the development of your application, or even if you use external suppliers .
But overall we can say that it is the team in charge of the product that is responsible for regularly updating the dependencies.
In many organizations, the development team is responsible for maintaining and updating dependencies. The developers regularly monitor updates (we will see a little later how to do this using tools), evaluate their impact on the project and make the necessary updates.
In some companies, a devops team may be responsible for managing dependency updates, especially those related to infrastructure.
Typically, security teams are responsible for tracking vulnerabilities and ensuring that necessary patches are applied quickly.
The continuous integration and continuous deployment (CI/CD) process plays an important role in automating dependency updates as much as possible in your CI/CD pipelines. Not forgetting automated tests to ensure that updates don’t break the project.
In a DevOps / DevSecOps approach, this is often a shared responsibility: in many teams, the responsibility for updating dependencies is shared between developers, security managers, and operational teams.
The question also regularly arises: to what budget should these actions be allocated?
It is crucial to treat dependency updates as standard, normal maintenance because they contribute to the stability, security, and performance of the application. Ignoring these updates can lead to security risks, bugs, and compatibility issues. Therefore, allocating an adequate budget, included in the project, for these activities is a wise decision to ensure the medium and long term viability of your project.
In any case, it is essential to clarify roles and responsibilities within your team or organization to ensure that dependency updates are handled efficiently and responsibly. Clear communication and collaboration between different stakeholders is essential to ensure the security and stability of your application.
The first thing to consider is reducing the number of dependencies: less is more!
When we look at the number of dependencies in our applications, it’s often scary. Most of the time, our application dependencies provide much more than the functionalities actually used. Just like our Docker images are often full of unnecessary packages!
Clean it up and you will gain in simplicity and ease of maintenance, security, stability and even performance (all at a cost)!
OWASP publishes a list of ten typologies of security vulnerabilities, called the OWASP TOP 10. The one that interests us today is number 6 in the 2021 ranking “Vulnerable and not updated components”.
The question that interests us will therefore be "How can we ensure that our projects do not include vulnerable dependencies?"
Standardizing and pooling dependencies in software management can significantly contribute to reducing maintenance effort.
By standardizing and pooling dependencies, you can avoid duplication of software components. Rather than having multiple instances of the same dependency used disparately in different projects, you can centralize the use of that dependency. This reduces the total number of dependencies, thereby simplifying management.
Standardization also means that you use the same versions of dependencies across all of your projects. This ensures uniformity and consistency between different parts of your software infrastructure. It’s easier to manage and maintain a smaller set of dependency versions.
For your own developments, having a versioning system respecting certain principles such as "Semantic versionning", reproducible and automated Release management is essential to better control, simplify and reduce your costs in this dependency management.
This sharing often involves having one or more expert teams in charge of governance and defining maintenance rules.
Today, many languages include package managers to work with dependencies.
For example, there is Maven with its plugin "Versions" which is used when you want to manage the versions of artifacts in the POM of a project.
In particular the "mvn versions:display-dependency-updates" task checks for new dependency updates.
NPM also includes a native tool npm-audit which submits a description of the dependencies configured in your project to your default registry and requests a report on known vulnerabilities.
In particular "npm audit fix" does the scanning for vulnerabilities and automatically installs all compatible updates for vulnerable dependencies.
Each language will have this type of tool to update obsolete or vulnerable dependencies, which is already a good first step but it remains a relatively manual action that a developer must do or an action to include in his pipeline which will be accompanied by a blocking “quality gate” step. In addition, it depends on each language and you also have to add the container part of system dependencies and base images…
Why not go a step further and automate the detection of dependency updates for your applications?
The idea is to be able to automatically detect, in a Git repository, a set of technologies, to deduce the necessary updates and to automatically trigger a Pull Request.
For example, Dependabot is a GitHub application that will access your repositories using an access token. Every day, it will analyze the dependency files (Java, JS, or others like Docker) and look for those that can be updated. If one of the dependencies is obsolete, Dependabot opens a Pull Request to replace it. You must then check the execution of the tests, analyze the library changelog and make a decision. Then accept the update by merging the PR or ignore the new version.
Note that Dependabot exists for Github and Gitlab:
Renovate will therefore also scan the source code of your repositories to check if there are any dependency updates. If this is the case, it will automatically create Merge Requests for their update. In addition, if your CI is complete and your unit tests too, you will have almost automatic validation of these modifications.
It will go a little further by providing more advanced features:
Automating dependency updates can only work if you have regression testing to rely on.
The aim is to detect potential problems or confirm stability and therefore reduce risks while speeding up the update process with controlled maintenance costs.
Regularly updating dependencies is a crucial step in managing the security, stability and performance of your applications. Ignoring updates can lead to vulnerabilities, bugs, and compatibility issues that can negatively impact your project in the long run.
The OWASP Top 10 highlights the importance of dependency management, especially when it comes to vulnerable and obsolete components. It is essential to closely monitor dependency updates and take immediate action in case of critical vulnerabilities or important security patches.
However, updating dependencies is not a simple task. It requires time, testing and appropriate management to minimize the risk of disruption. It is crucial to consider this as standard maintenance and allocate an adequate budget for it.
To make this process more efficient, you can reduce the number of unnecessary dependencies, standardize and pool dependencies where possible, and automate update detection and management using tools like Dependabot or Renovate. However, automation can only work effectively if you have regression testing in place to ensure the stability of your application.
Ultimately, regularly updating your dependencies helps keep your application up to date, secure and healthy, which is essential to meet the changing demands of the technology world and to protect your project from emerging threats. including Supply Chain Attacks.