Research

Abandoned Dependency Risk Study

The Safeguard Research team measured how much abandonment exists in real dependency graphs, how it correlates with risk, and what to do about it.

Shadab Khan
Security Engineer
7 min read

Every dependency graph we have ever audited has abandoned code in it. Sometimes the abandonment is obvious: a README that apologises, a last commit years old, an issue tracker of pleading pull requests. More often it is quiet. A package still resolves, still installs, still passes tests, and still ships, while the humans who wrote it have long since moved on.

The Safeguard Research team set out to measure abandonment at scale, correlate it with realised security risk, and produce guidance that security and platform teams can apply without asking engineering to rewrite half the codebase. This post summarises what we found.

How does the team define abandonment?

We define a package version as abandoned when it satisfies at least two of four signals: no commit to the default branch in 18 months, no published release in 24 months, an issue tracker with a ratio of open to closed issues that has been growing for at least a year, and a sole maintainer with no recent activity across any of their published packages.

We use multiple signals because any single signal is noisy. Small, stable libraries can legitimately go years without a release. A project maintained by a company can have very low issue-tracker activity because most work happens inside a private repository. Multi-signal agreement produced a label we were willing to trust.

We did not require that a package be broken. Many abandoned packages still work perfectly well. The question we cared about was whether there is anyone to respond if something stops working, and whether there is anyone to respond if the package is compromised.

How common is abandonment in real dependency graphs?

In our corpus, the share of resolved transitive dependencies meeting the abandonment definition sat in the mid-teens to mid-twenties, depending on ecosystem and application size.

JavaScript and Python graphs showed the highest abandonment rates, in part because those ecosystems produce a larger long tail of small, single-purpose libraries. Java and Go showed lower rates, partly because projects tend to be larger and organisationally backed, and partly because dependency graphs are shallower to begin with.

The rate at the direct-dependency layer was lower, usually in the single digits, which tracks with how teams choose their direct dependencies deliberately. The abandonment problem is overwhelmingly a transitive problem. It is the dependencies of your dependencies that have gone quiet.

Does abandonment actually correlate with security incidents?

Yes, with a strong but not overwhelming correlation. Abandoned packages were disproportionately represented in the set of packages we saw compromised or used as attack entry points over the last three years.

Specifically, in our historical data, abandoned packages were roughly two to three times more likely to appear in a documented supply-chain incident than a like-for-like active package with similar download volume. The most common incident classes were maintainer account takeover, ownership transfer to an anonymous or suspicious party, and slow merging of malicious pull requests that a more active project would have rejected.

The correlation is not perfect because abandonment is not the proximate cause of compromise. It is an enabling condition. A healthy project with active review and a diverse maintainer base is a much harder target, and attackers know it.

Which abandonment patterns are most dangerous?

The riskiest pattern we identified is the "popular, sole-maintainer, silent" profile: high download volume, a single maintainer, and a long gap in both commits and issue responses.

These packages combine three unfortunate properties. They are attractive to attackers because the download volume promises scale. They have no redundant human attention on them, so a malicious change or account takeover can sit undetected. And because they are popular, they tend to be locked in deep in transitive graphs, where direct consumers are not paying close attention.

A secondary risky pattern is the "recently transferred" profile, where a dormant package has new activity from a maintainer with no prior history in the ecosystem. Ownership transfers of dormant popular packages are a known attacker technique, and several high-profile incidents of the last few years fit this pattern.

The lowest risk abandonment pattern, perhaps counter-intuitively, is a small, stable utility with no recent activity, no recent issues, and no ownership churn. These packages tend to be abandoned in the sense that nobody needs to change them rather than in the sense that nobody is watching them.

What does abandonment do to the vulnerability queue?

Abandoned packages break the assumed remediation path for vulnerability management, because there is no upstream to ship a fix.

In our corpus, roughly 15% to 25% of advisories affecting abandoned packages remained unfixed upstream at the time the advisory was published, compared with single-digit percentages for active packages. When a fix did eventually land, it was usually because a consumer submitted a patch, the package was forked, or the ecosystem curators stepped in.

For a security team, this means that a material share of the actionable vulnerability queue has no vendor-supplied remediation path. The choice is to pin to an unpatched version with compensating controls, switch to a maintained alternative, fork and carry a patch internally, or remove the dependency. None of those options is cheap, and all of them need to be resourced.

What should teams do about it today?

The highest-leverage move is an abandonment inventory at the transitive layer, with tiered action based on the risk pattern, not a blanket ban.

First, run an inventory. For every direct and transitive dependency, score it against the abandonment signals and expose the result in the same developer surfaces you already use for vulnerabilities. The single most important insight is usually not a surprise so much as a shock at the scale.

Second, segment the list. Pin the small, stable, low-risk abandoned utilities, track them as accepted debt, and move on. Treat the popular, sole-maintainer, silent cluster as active risk and plan replacements or internal forks for the most exposed ones. Watch the recently-transferred cluster with additional scrutiny, including locking versions until the new maintainer has established a track record.

Third, change new dependency intake. Add maintenance posture to the review criteria for new direct dependencies. A package that looks healthy today but has a single maintainer and no release cadence is a future abandonment risk you are choosing to accept.

Fourth, contribute. Small, well-reasoned contributions to packages you depend on are the cheapest form of supply-chain insurance. A maintainer who knows you exist is a maintainer who will answer an email about a suspicious pull request.

How does this intersect with regulatory and procurement pressure?

Abandonment is one of the hardest topics for software bill of materials and procurement disclosure regimes, because the definition is fuzzy and the remediation is expensive.

Several large procurement frameworks now require vendors to attest to some form of maintenance posture for their dependencies, and we expect that trend to accelerate. Teams that already have an abandonment inventory, and a policy for what they do about it, will answer those questionnaires in hours rather than months. Teams that do not will end up either declining to bid or making attestations they cannot defend.

What this means

Abandonment is a silent, pervasive, and growing share of the real risk in open-source software. It is not captured well by CVE counts, is not fixed by upgrading to the latest version, and is not solved by adding another scanner. It is a maintenance problem that has to be measured, segmented, and budgeted for, the same way engineering organisations budget for any other class of technical debt.

The teams that win at this problem are the teams that treat abandonment as an ongoing property of their software, not an occasional clean-up exercise.

How Safeguard.sh Helps

Safeguard.sh scores every direct and transitive dependency against a multi-signal abandonment model and surfaces the risk patterns described in this post. We identify the popular, sole-maintainer, silent packages where the expected attacker payoff is highest, flag recent ownership transfers on dormant packages, and recommend maintained alternatives where they exist. Our platform connects abandonment findings to your vulnerability queue so that unfixable advisories are budgeted, not ignored, and to your procurement attestations so that your maintenance posture is defensible. Customers use Safeguard.sh to turn abandonment from a vague worry into a tracked, shrinking list.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.