Socwise logo
Lesku Gergely
06/04/2026

Not enough to know what we’re developing—also need to know what it’s made of

Lesku Gergely
Modern apps are built from countless third-party components. Learn how SCA reveals hidden dependencies, vulnerabilities, license risks, and supply chain threats.

One of the fundamental truths of modern application development is that we rarely write everything from scratch anymore. Development teams use ready-made libraries, frameworks, open-source components, and third-party packages to deliver faster and focus on business logic. This isn’t a problem in itself; in fact, the open-source ecosystem is one of the main reasons software development moves at such a fast pace today. The question is rather whether we know exactly what we’re incorporating into our applications—and what risks these entail.

These days, we don’t write apps—we build them

In a modern application, custom-developed code often constitutes only a small but business-critical part of the entire system. Authentication, HTTP handling, database connections, logging, file management, and even certain elements of the user interface are frequently built on top of third-party components.

This makes development more efficient, but it also creates new layers of risk. When we use an external package, we don’t just adopt its functionality, but also its entire dependency chain, vulnerabilities, license terms, and maintenance status.

Packages selected directly by developers are called direct dependencies. These are typically listed in the project’s manifest files, such as a package.json, pom.xml, or similar file. The real blind spot, however, often doesn’t start here, but with transitive dependencies: these are the components that weren’t chosen by the developer, but are pulled in by the selected packages.

A single popular framework can bring in dozens or even hundreds of additional packages. These become part of the application just the same, even if the developer never encounters them by name.

Why isn't reviewing your own code enough?

Static analysis of your own code remains important. Security testing of business logic, custom functionality, and in-house components is essential. But on its own, it no longer provides a complete picture.

At the end of the build, it is not the repository that goes into production, but a deployable artifact: for example, a container image, a JAR file, a ZIP package, or another application package. This contains not only your own code, but also direct and transitive dependencies, along with their licenses, metadata, and vulnerabilities.

That is why it is not enough to say that “your own code is fine.” You also need to see exactly which components were ultimately included in the application, in which versions, under which license terms, and with what known or potential risks.

This is where SCA—Software Composition Analysis—comes into play.

What does the SCA offer?

The purpose of SCA is to make the application’s complete list of dependencies visible. It shows not only which direct packages we use, but also the transitive dependencies they bring along.

A more advanced SCA tool offers even more:

  • maps the exact versions of components;
  • identifies known vulnerabilities;
  • displays licenses and licensing obligations;
  • indicates if a package is outdated or unmaintained;
  • helps understand how a component made its way into the application;
  • supports the generation of an SBOM, or machine-readable software bill of materials.

The difference between a simple package manager command and an SCA solution is significant. A package manager can list dependencies, but typically does not provide a complete security and licensing context. It does not show which components carry critical vulnerabilities, which version is worth updating to, or how a transitive component made its way into the application.

A new era of supply chain attacks

Development based on third-party and open-source components is an attractive target for attackers. In many cases, they do not attack the application itself directly, but rather the environment where the package is deployed: a developer’s laptop, a CI runner, a build host, or a container build environment.

These risks can manifest in several ways:

  • exploitation of known vulnerabilities;
  • outdated or unmaintained components;
  • overly broad version ranges;
  • discrepancies between manifest and lock files;
  • leakage of secrets, tokens, or API keys;
  • malicious packages;
  • typosquatting or dependency confusion attacks.

In the case of typosquatting, the attacker publishes a package with a name very similar to that of a known package, hoping that the developer or the build process will mistakenly pull it in. In the case of dependency confusion, the attacker creates a public package with a name identical to that of an internal package, and the build system resolves the dependency from the wrong source.

Particularly dangerous are cases where the malicious code runs during installation, for example in the form of a post-install script. In such cases, even if the application does not call the package in question while running, this offers no protection. The build environment itself becomes a target for attack.

New risks in AI coding

The emergence of AI-based coding agents adds a new dimension to the problem. These tools can accelerate development, but they can also “hallucinate” package names: that is, they may suggest packages that sound plausible but do not actually exist, which the developer or the agent itself may then attempt to install.

If an attacker recognizes that certain hallucinated package names are recurring, they can publish these with malicious code in a public registry. From this point on, the risk is no longer theoretical: if the agent or the developer pulls the package, compromise can occur.

This clearly demonstrates that software supply chain security is no longer merely a vulnerability management issue. It is an ecosystem-level problem in which development processes, build environments, package management, AI tools, and operational controls all play a role.

Running SCA for the first time can be shocking

Anyone running an SCA scan on an older or larger application for the first time may easily be faced with hundreds or even thousands of findings. This can be daunting at first, but it doesn’t necessarily mean the development team did a poor job.

Keeping external packages up to date is an ongoing task. If this is neglected for an extended period, it’s natural for vulnerabilities, outdated versions, and licensing risks to accumulate. Furthermore, some of the results may be false positives—that is, vulnerabilities that cannot be exploited in the given application context.

However, this does not mean that transitive dependencies should automatically be ignored. A vulnerability in a deeply nested package can indeed be exploitable if the application’s data flow eventually reaches it. This is why triage is important: you must decide which findings pose a real risk and which can be addressed with lower priority.

Triage or upgrade?

One of the practical challenges of SCA is that it is often unclear when it is worth performing a deep triage and when it is simpler to just upgrade. In some cases, proving that a vulnerability cannot be exploited can be almost as much work as the upgrade itself.

Particular caution is needed when directly updating transitive dependencies. Technically, it is possible in many environments to override a version of a package further down the dependency chain, but this can introduce functional risks: the direct package may not have been tested with the version we are forcing it to use.

For this reason, many teams prefer to update direct dependencies to a version that already pulls in safe transitive packages. A good SCA tool can help with this as well: it shows which direct dependency needs to be updated to which version in order to eliminate the vulnerable component at a deeper level.

SCA is not just a single pipeline step

A common mistake is to treat SCA as a simple CI/CD pipeline step: “we just add a scanner to the build, and that’s it.” This dangerously oversimplifies the issue.

In fact, SCA can add value at multiple points in the software development lifecycle:

During development, it can provide early feedback if someone attempts to include a vulnerable or unlicensed package. At the pull request or merge request level, it can serve as a checkpoint: it shows what new dependencies, vulnerabilities, or policy violations a change introduces.

During the build and release phases, it can verify what the actual artifact contains. This is particularly important because what ends up in the build isn’t always what we see at first glance in the source code. At release, an SBOM can be generated, which can serve as crucial evidence during audits, supplier requirements, and incident management.

In a production environment, SCA can also support continuous monitoring. What appears to be a secure component today may turn out to have a critical vulnerability tomorrow. In such cases, we need to be able to respond quickly: are we using the affected package, in which application, in which version, and who is responsible for the fix?

When is the best time to implement it?

For startups and rapidly evolving products, the timing of SCA implementation is particularly important. In the earliest stages, when the product is still finding its footing, overly strict controls can easily lead to inflexibility. At the same time, the longer we delay implementation, the greater the technological and security debt will become.

The decision should be made on a risk-based basis. It matters how many users the system has, what data it handles, what customers it serves, and what market or regulatory expectations apply to it. For a B2B product, for example, a security audit by a large enterprise customer may in itself necessitate the existence of SCA, SBOM, and vulnerability management processes.

It is advisable to begin implementation gradually. The first step could be an “alert-only” mode, where the system does not yet block the build but only highlights the issues. Policies can then be tightened on a per-application and per-risk-level basis.

The most important lesson

The use of open-source and third-party components should not be avoided, but rather managed. Modern software development relies on them, so the goal is not to rewrite everything in-house. However, it is a fundamental requirement that we know exactly what components our application consists of, how they were incorporated, what vulnerabilities and licensing obligations they carry, and what we must do if a new risk emerges.

In this regard, SCA is not merely a technical tool, but a development and security control layer. It makes software composition visible, supports triage, aids in SBOM generation, and speeds up incident management.

So the question today is no longer whether we use third-party components. We do. The real question is whether we know exactly what we’re using—and whether we’re able to respond in time if any of them become a risk.

crossmenu