Matthew de Klerk
on 10 September 2025
What are dependencies, and how do you secure them?
Open source software is everywhere. Research shows that around 97% of codebases contain open source software, and it’s clear to see why. It’s always magical to realize that there are thousands of free-to-use, ready-built programs and code repositories that solve problems you’d otherwise need to spend weeks building the solutions for from scratch.
However, like with all software, you still need to ensure that your software supply chain is secure and safe to consume. This means managing two things: dependencies, and (consequently) security risks. In this blog, we’ll explore what dependencies are, why they matter, and why they cause so many problems in vulnerability management.
What are dependencies?
In software engineering, dependencies refer to external components, libraries, modules, or services that a software application or system relies on to function correctly. These external elements are not part of the core codebase but are integrated into the software’s build or runtime environment. All of these dependencies come in two forms: direct dependencies and indirect dependencies (also known as transitive dependencies).
What are direct dependencies and what are transitive dependencies?
Direct dependencies are all the libraries that you explicitly declare, include, or use in your software project or code. These direct dependencies are typically essential or mandatory for your project to work properly. Direct dependencies are, by definition, directly declared by the project team.
In contrast, indirect dependencies are the dependencies of your direct dependencies: libraries, modules, or components that your direct dependencies rely on to function. These indirect dependencies are not explicitly declared, but are pulled in through the direct dependencies.
An example of an indirect dependency might be seen in a Node.js application which relies on Express, which in turn needs the debug package to function. By this transitive function, your application would require ‘debug’ to function properly – meaning that if your project uses node.js it will be indirectly dependent on the ‘debug’ package.
Now, dependencies are clearly a good thing, given the DRY principle of software engineering (‘Don’t Repeat Yourself’): you want to avoid as much as possible duplicating code and repeating logic, and dependencies are a great way to represent useful functions without stuffing your codebase with duplicating all the components, packages, and libraries in your codebase.
However, dependencies still need to be taken care of. Given the large number of direct and indirect dependencies that software can have, projects can quickly develop large, exceedingly complex dependency trees that make it very difficult and time-consuming to manage their security, patch them or upgrade them to new versions where necessary, and resolve any errors that arise over time from their use.
Why are dependencies a risk in software development?
Dependencies can be a problem in your software security for a number of reasons. Let’s take a look at a few.
Dependencies can mean vulnerabilities
If your application relies on a particular package, framework, or library that becomes affected by known vulnerabilities, your app could be compromised or at risk.
Generally speaking, dependencies contain several flaws that can introduce risk into your programs or supply chain.
For example, attackers can exploit security flaws present in many libraries and packages. These flaws can range from common vulnerabilities like SQL injection, command injection, authentication bypass, and buffer overflows, to more complex logic errors or insecure configurations. Exploiting such weaknesses can allow attackers to gain unauthorized access, manipulate data, or disrupt services.
Sometimes, malicious actors can introduce malicious code into legitimate packages, meaning that anyone who uses this otherwise ‘trustworthy’ project will have their software supply chain compromised.
Here are some ways malicious actors can attack your systems through dependencies:
Account compromises
This happens when a developer’s credentials are compromised, giving attackers a legitimate vector to upload malicious code into seemingly safe repositories or libraries. This is one of the biggest threats in software supply chain management, given how many cyber attacks are aimed at gaining access to accounts that have privileges in a system.
Dependency confusion attacks, or namespace attacks
A dependency confusion attack happens when one package or library is confused for another. This can happen when an attacker uploads a malicious package with the same name as legitimate, internal, or private packages, into a different namespace, but perhaps the most common approach is to name something very similar to the legitimate project.
Hallucination attacks
This new method of attack has gained traction with the rapid rise of GenAI. Quite often, a GenAI tool will hallucinate when generating code for user projects, referencing packages or libraries that don’t exist. Attackers figure out what names are consistently and recurrently being hallucinated by LLMs and then register those names, may even upload functioning code to them at first, but then eventually they upload malicious code to them, waiting for the day a dev uses GenAI-created code that ‘looks fine’ in their project.
Dependencies can increase your attack surface
Many libraries or packages in your codebase contain code for your project to execute or reference. That means that every package is a potential pathway for malicious actors or code to make its way into your apps and systems, or is a place where bugs, out-of-date code, or other issues can cause your project to fail.
Dependencies can make compliance hard to achieve
Many cybersecurity regulations and security standards have strict requirements around how you use, update, and secure your dependencies. For example, FedRAMP security controls have many security requirements for software, including that you fix high-risk vulnerabilities within 30 days – and this implicitly applies to any install dependencies.
Not properly securing or updating your dependencies could lead to a loss of your compliance status.
How to patch dependencies and transitive dependencies
There are two ways to deal with dependencies.
The first is to not have any dependencies at all in your project. That’s problematic for a very obvious reason: there is so much useful code out there that you can use in your project instead of writing it all yourself from scratch. Saying “well, let’s just avoid dependencies” is unrealistic, and creates far more hurdles and resource demands than it is worth.
The second strategy is to ensure that you manage these dependencies, have visibility over your entire software supply chain, and take a risk-based approach to mitigating threats to your supply chain, including ensuring that they are patched against known vulnerabilities.
This second strategy is the far more reasonable one, and it’s the industry standard when dealing with direct and indirect dependencies. On top of this, you should also ensure that you’re only using the smallest number of mandatory packages, in order to minimize your total number of dependencies. Try to avoid ‘nice to have’ packages that aren’t required for core functionality.
Unfortunately, matching and managing dependencies is not as simple as just getting updates from public repositories. These open source software and public package repositories, such as the npm registry or PyPI (the Python Package index), do give you access to a huge number of high-quality software – but as we’ve pointed out above, these public repositories are not immune to attacks. And that means risks in your software supply chain.
The common approach to dealing with these risks is scanning for outdated or at-risk packages, and updating them to the latest fixed versions. In some cases, there might not be upstream updates available, meaning some uncommon cases where you might have to fix specific flaws in the version of the package you depend on.
However, both of these approaches can be time-consuming and manual, or slow to catch malicious components or actively-exploited vulnerabilities before a security incident occurs. In fact, according to IDC research, only 41% of organizations are confident that they can patch vulnerabilities within desired timeframes.
The best way to patch and deal with dependencies
Organisations need two things to address the root issue that leaves them vulnerable:
- A trusted source that vets and monitors software packages
- Timely, automatic security updates that do not break functionality and maintain software stability
Let’s explore each of them.
A trusted source for your software supply chain
This is needed for the entire software supply chain, including your everchanging list of transitive dependencies. The great news is that you can get all of this from your OS. Ubuntu is a great foundation for even the most complex of deployments, and it’s trusted by thousands of developers around the world. In fact, Ubuntu is the most popular Linux distribution in the world.
An Ubuntu Pro subscription takes that securely designed baseline even further, giving you access to comprehensive security maintenance for thousands of open source packages on top of the operating system, as well as hardening and patching automation tools that enable you to apply patches at scale. It’s free for personal users, and up to five machines – and there are free trials available for enterprises.
This has advantages over the approach of constantly following the latest upstream version. It’s simpler, faster, involves less manual effort, and allows you to consume updates for your dependencies in one single place, rather than an app-by-app or project-by-project basis – making for easier monitoring and compliance work.
Timely, automatic security updates
You need a trusted source for your patches and package, but equally critical is having some way of applying these vital updates at regular intervals. The best way to do this on systems using Ubuntu is through Ubuntu Pro, a service that automatically applies available fixes for all your software. Ubuntu Pro is far more efficient and effective than simply following the many upstream versions of the packages and libraries you use.
This approach also has several advantages over manual or alternative methods. First, it’s less time consuming, as all your packages are updated without needing your direct input. Second, it usually delivers security updates and maintenance across a much wider range of packages and libraries (in the case of Ubuntu Pro, you’ll get updates to all packages available in both the Main and Universe repositories, so you’ll get both community-maintained OSS and the Canonical-supported OSS). Finally, these fixes are typically backported to older or legacy versions of software or Ubuntu. Doing this work yourself, especially in software environments with frequent version changes (like PHP or Node.js) is skilled, time-consuming work. And why do that work yourself when we do it already, thousands of times a year, for millions of devices and end users?
Our approach to vulnerability management has been proven to help companies secure their operations, systems, and services, and simplify the pathway to meeting demanding regulatory compliance. For example, we’ve helped large data analytics companies, and SaaS providers like Lucid meet FedRAMP requirements, through our cryptographic modules and vulnerability management processes.
Conclusion
In summary, managing software dependencies is crucial for maintaining a secure and stable software supply chain. While dependencies offer significant benefits in terms of code reuse and efficiency, they also introduce potential vulnerabilities and increase your overall attack surface. Effective dependency management involves understanding the difference between direct and transitive dependencies, recognizing the risks they pose, and adopting proactive strategies for securing and maintaining them. Relying on trusted sources for software packages and implementing timely, automatic security updates, like those provided by Ubuntu Pro, can significantly enhance your organization’s security posture and simplify regulatory compliance. By taking a strategic approach to dependency management, you can harness the power of open source software while minimizing your overall risk profile.
If you want to know more about how Ubuntu Pro helps you with comprehensive vulnerability management for your open source dependencies, visit ubuntu.com/security or ubuntu.com/pro.