Reducing the number of dependencies for security

In the light of recent NPM supply chain attacks, I believe it would be greatly beneficial for us to reduce the number of dependencies in both XS and Cristal as much as we can.

In Cristal for instance, we sometimes import lodash-es to use a single, ~10 LoC debounce function. Given the low amount of code and complexity this represents, we could very well get rid of it and integrate it inside our codebase.

The same goes for several other dependencies we currently have. One of the arguments against it was that it reduced our maintenance efforts ; on which I disagree again, as upgrading packages is not always simpler, and very simple code pieces don’t need maintaining most of the time anyway.

On the security aspect, one proposed mitigation would be to wait for a few days before upgrading dependencies. Thing is, more and more people are gonna go this way, which will increase the time required to discover infected dependencies, so in my opinion it’s a necessary but not sufficient effort.

I personally (very) strongly believe we should reduce our dependencies, as it reduces our attack surface, and as a bonus even simplifies maintenance as we don’t have to worry about breaking changes on their side.

What is your opinion on that subject?

I agree with you that it does not make much sense to add a dependency if you just use a very simple method from it. That being said, I cannot really think of a single example like this on Java side.

1 Like

Thanks for the info.

I’m not sure if this problem exists in XS, as I’m not familiar at all with its codebase. I know this problem exists in Cristal, so I want to ensure we don’t have the same in XS, and also that we’ll never have it :slight_smile:

While I’m reasonably aware of Java dependencies, it’s less the case for frontend ones in XS, and we could have the case too (especially since we are going to reuse more and more common components).

Right, that’s a point I didn’t even mention, but adding a dependency in a common package increases the attack surface on all projects that depend on it.

To give you an equivalent in the Java world, it is like discussing if we want to remove dependencies to commons-* packages because the provided methods and classes are individually simple.

Which one?

We don’t use lodash only for debounce, and it’s likely that we are going to use more of it in the future.

The threat of security is very vague and is not yet backed by facts in your proposal. How can you guarantee that our small development team will do better regarding security (among other non-functional aspects) than the package maintainers?

Of course this comes at a cost, but this is part of our job to select dependencies carefully and to perform analysis during upgrades.

To take the example of lodash, it has been upgraded exactly zero time over existence of Cristal. So in my opinion, we only got many utility functions for free that we can trust and don’t have to maintain.

And to expand beyond the specific case of lodash, most of the dependencies we use are essential to the development and maintenance of Cristal, and it would be absolutely impossible for us to develop (and maintain) them.
The time spent upgrading is orders of scales lower than the time we would spend developing them.

In conclusion, in light of the currently exposed arguments, I’m -1.

2 Likes

That’s not really what @ClementEXWiki explained, and not at all what I said. We are using a lot of methods from Apache commons-* modules.

To give you an equivalent in the Java world, it is like discussing if we want to remove dependencies to commons-* packages because the provided methods and classes are individually simple.

I disagree, as commons-* are very well-supported packages with a strong team behind it which vet everything from programming to publishing, which isn’t true for lodash-es.

We don’t use lodash only for debounce, and it’s likely that we are going to use more of it in the future.

Sorry I should have specified in my post, I’m specifically talking about packages where we only use lodash-es for debounce. In packages where we use several other functions, some of which sometimes complicated, then it may make sense to leave the dependency here.

The threat of security is very vague and is not yet backed by facts in your proposal. How can you guarantee that our small development team will do better regarding security (among other non-functional aspects) than the package maintainers?

The content of these functions doesn’t really have anything to do with security. They are basic programming functions, and security isn’t really a concern here.

My concern is supply chain attacks. Is someone takes control of the repository and/or the NPM package publishing, they can inject some malicious code, which wouldn’t happen with our own.

To take the example of lodash, it has been upgraded exactly zero time over existence of Cristal. So in my opinion, we only got many utility functions for free that we can trust and don’t have to maintain.

That’s a good point, I thought lodash would be upgraded regularly by Dependabot along other packages. If we basically never update it, given it’s not a security-sensitive package, then it’s fine leaving it as it is I think.

And to expand beyond the specific case of lodash, most of the dependencies we use are essential to the development and maintenance of Cristal, and it would be absolutely impossible for us to develop (and maintain) them.

This post is not only to reduce the number of dependencies that we have today, we also to ensure we are gonna be very careful when choosing to add new dependencies to the project.

My initial post wasn’t worded correctly, so I apologize for the confusion, I specifically targeted specific packages like lodash-es (which finally seems like it may stay given it’s not updated often) and ensuring we’re careful going forward.

Well, that’s already part of our rules :wink:
The best practice is to do a comparison of several options and to make a proposal when we need to introduce a dependency.
Sustainability, quality, and security being parts of the criteria.

But then we end up with two versions of the same thing, leading to:

  1. increased maintenance cost
  2. a double impact on the bundle size (while if we use lodash everywhere, only a single method is bundled in the final distribution)

I’m not sure I understand the proposal. It seems it’s more a brainstorming than a proposal.

The parts I see that are a proposal are the following:

I don’t really agree with this, at least not the way it’s phrased, so I’ll say -1 for now (even if it’s not a vote ;)). Most of the time we will upgrade for bugfix versions which are correcting bugs, including security issues. Delaying the upgrade would be negative.

If you’re referring to upgrading to major versions, then sure, and it’s almost always the case anyway that we wait for at least a few days after upgrading (since we need to evaluate the consequences). OTOH your proposal doesn’t say what “a few days” mean. Is it 2 days? Is it 2 months?

I’m very -1 on that as a general principle. And no, it doesn’t reduce maintenance (above a few lines of code). But we need to continue our rule of choosing well our dependencies (active code base with regular releases, several active committers, fast answers to questions, etc). Note that we haven’t written these rules down in our dev guide and we could.

Thanks!

2 Likes

One detail: it’s not because there’s a CVE for a dependency that we are affected by it. We may not use the method having the security issue for example. So it’s not a de facto rule that a larger code base will increase our surface attack.

The recent supply chain attacks on NPM didn’t introduce security vulnerabilities in single methods but introduced credential stealing malware in central parts of the code like installation scripts, meaning that a developer’s machine was infected the moment the dependency was installed. I think this is the attack surface @ClementEXWiki is referring to here. The more dependencies we have, the more likely it is that some developer’s account is compromised and a malicious release is uploaded. And when we update fast before the malicious release is detected and removed, some or potentially all developers’ machines are compromised, potentially giving credentials for GitHub, Nexus or other critical infrastructure to the attacker.

We need to be careful with dependencies and their upgrades, making sure that dependencies are well-maintained, removing dependencies that aren’t maintained anymore, and we also need to be careful when upgrading dependencies, ensuring that upgrades aren’t introducing backdoors or malware.

1 Like

To summarize the discussion briefly, I think the consensus is

  1. We need and want to use dependencies.
  2. We have best practices for the selection and maintenance of dependencies.
  3. We are aware of the risks caused by supply chain attacks.

But, we don’t have in-depth knowledge of the best strategies to address the risks caused by supply chain attack.
Therefore, I think an interesting next step is to document ourselves on the topic (for npm, but also for maven) to find what we can do.

PS: I found out that the use of “Vulnerable and Outdated Components” is part of OWSAP top 10 A06 Vulnerable and Outdated Components - OWASP Top 10:2021, so the risk seems to be on not upgrading enough :slight_smile:

1 Like

That was the risk (more than?) 4 years ago, seeing large supply chain attacks in the wild is something more recent I think, so I would expect that we see at least an update on this in the OWASP Top 10 2025 that should be published in about a month.

2 Likes