Skip to main content

Open Source and Maintainer Debt: The Staff You Never Hired

Last updated . Sources are named and dated inline - how we source claims.

Your dependency graph is a staffing plan nobody approved. Somewhere inside it is a package maintained by one unpaid person in their evenings, and your release schedule quietly depends on how their year is going.

Single-maintainer concentration, unpaid maintenance, abandonment, and trust that can be socially engineered are all technical debt. They are simply held on somebody else's balance sheet until the day they land on yours.

The Other Half of Dependency Risk

Most dependency advice is about consumption: pin your versions, scan for vulnerabilities, keep upgrades small, produce a bill of materials. Our dependency management guide covers that side thoroughly. But it treats each package as a fixed object with a version number and a CVE list, which is the wrong mental model.

A dependency is not an artifact. It is an ongoing service delivered by people, most of whom you have never met and none of whom you pay. The version you pinned last quarter is safe only for as long as somebody keeps looking at that code. When they stop, nothing visibly breaks. Your tests still pass. What changes is that the next security report arrives at an inbox nobody reads.

This is maintainer debt: the gap between the reliability you assume from your dependencies and the human capacity that actually exists behind them. Scanners cannot see it, because scanners look at code and this is a question about people. And it runs both ways. If your organization publishes packages, you are the maintainer somebody else is quietly depending on, and the backlog you have not triaged is their debt too.

Nearly every commercial codebase now rests on this arrangement. Black Duck's current audit round reports that "Only 2% of the codebases we audited contained no open source components". That is not a warning about open source quality, which is frequently excellent. It is a statement about concentration: an enormous amount of commercial software depends on a volunteer base that was never sized for the load.

Bus Factor in Your Supply Chain, Not Your Team

Every engineering organization worries about the bus factor inside its own walls. Who is the only person who understands billing? What happens if they leave? Those conversations happen in staff meetings and get tracked in onboarding plans. Almost nobody has the same conversation about the packages that make up most of the shipped binary.

The research is not reassuring. Avelino and colleagues built an estimator for the truck factor -- the minimum number of developers who would have to be hit by a truck before a project is incapacitated -- and applied it to 133 popular GitHub projects in 2016. The majority, 65 percent, had a truck factor of two or less. That corpus is a decade old and limited to popular projects, so it is not a claim about all software everywhere, but it establishes the shape of the problem.

The Linux Foundation's Census III study, published with the OpenSSF and Harvard's Laboratory for Innovation Science, reached the same conclusion with newer data. Reviewing commits across 47 of the top 50 non-npm projects, it found "17% of projects had one developer accounting for more than 80% of commits authored" and "40% of projects had only one or two developers accounting for more than 80% of commits authored". The report notes these findings run "counter to the typically held belief that thousands or millions of developers are responsible for developing and maintaining FOSS projects."

Concentration

One maintainer is one point of failure for releases, security response, and key custody. One person's credentials become the whole publishing pipeline: no second reviewer, no second signer, and nobody to notice when the first one acts out of character.

Invisibility

The risk sits several levels down the transitive graph, in a package you never chose and cannot name. You picked a web framework; you inherited four hundred packages, and nobody in your organization has read the maintainer list of any of them.

Latency

Abandonment is not an event with a date. Projects go quiet gradually, and the gap between "slow to respond" and "nobody is home" is obvious only in hindsight, usually on the day you need an emergency patch.

Case Study: xz-utils and Social-Engineering Trust Debt

The xz-utils backdoor is the clearest demonstration of what maintainer debt costs. It was not a coding mistake, and no scanner could have caught it in advance. It was a patient attack on one person's capacity, against a compression library that almost every Linux system depends on.

Russ Cox's assembled timeline records that an account using the name Jia Tan sent its first, innocuous patch to the xz-devel mailing list on 29 October 2021 -- an .editorconfig file. A commit authored under that address was merged in February 2022. By 30 November 2022 the README named "the project maintainers Lasse Collin and Jia Tan", and by the end of that year the account was merging commits directly. That is roughly fourteen months of ordinary contribution before any trust was misused.

Running alongside it was a pressure campaign. Accounts using the names Jigar Kumar and Dennis Ens complained repeatedly about the project's pace: "Patches spend years on this mailing list. There is no reason to think anything is coming soon." One wrote, in June 2022, "I am sorry about your mental health issues, but its important to be aware of your own limits." The messages read as frustrated users advocating for faster releases, which to a tired maintainer is exactly what they looked like.

What the original maintainer said publicly at the time is the part worth sitting with. Writing to xz-devel on 8 June 2022, Lasse Collin explained: "I haven't lost interest but my ability to care has been fairly limited mostly due to longterm mental health issues but also due to some other things." In the same message: "It's also good to keep in mind that this is an unpaid hobby project." An enormous amount of the world's computing rested on that sentence.

The payload surfaced on 29 March 2024, when Andres Freund posted to the oss-security mailing list after investigating unexpected SSH latency. His disclosure noted that "One portion of the backdoor is *solely in the distributed tarballs*" -- the malicious build step was not visible in the git repository -- and that the timing was extraordinarily lucky: "xz 5.6.0 and 5.6.1 have not yet widely been integrated by linux distributions, and where they have, mostly in pre-release versions."

The National Vulnerability Database, which tracks this as CVE-2024-3094, describes the mechanism plainly: "Through a series of complex obfuscations, the liblzma build process extracts a prebuilt object file from a disguised test file existing in the source code, which is then used to modify specific functions in the liblzma code."

Census III draws the connection explicitly, describing an attack that "included launching a pressure campaign on the solitary maintainer of the project to add a second maintainer, who later introduced the backdoor", and noting that given how many critical projects have a single maintainer, "many fear that similar attacks could occur in the future."

The lesson is not to distrust contributors. It is that a project with one exhausted maintainer has no capacity to be sceptical. Review, second opinions, and slow onboarding of new committers are safety mechanisms, and they are the first things dropped when the person doing the work has nothing left. Every hour of unfunded maintenance burden is also a reduction in a project's ability to defend itself.

Unpaid Maintenance is a Systemic Externality

Economists have a word for a real cost that lands on someone outside the transaction: an externality. Open source maintenance is one of the cleanest examples in the industry. A company ships a product, bills a customer, books the revenue, and the maintenance labour that made the product possible is absorbed by volunteers who receive none of it.

That is not only a moral complaint. It is a risk statement. Unpaid labour is uncontracted labour, with no service level, no succession plan, no on-call rotation, and no obligation to continue. When a maintainer burns out, changes jobs, gets sick, or loses interest, nothing entitles you to a replacement. Your incident response plan assumes a patch will exist; nothing guarantees it.

The externality also explains a pattern that confuses executives: the most critical packages are often the least maintained. Critical infrastructure code is usually old, unglamorous, and stable. It attracts no new contributors because there is nothing exciting to build, and no funding because nothing is visibly wrong. Attention in open source flows to new projects; the risk sits in the old ones.

What Burnout Looks Like From Outside

Issue responses get shorter and then stop. Releases slip from monthly to quarterly to annual. Open pull requests pile up untriaged. Then a maintainer posts something honest about their capacity and strangers reply that the project is dead and should be forked. That reply is the externality made visible: consumers with strong opinions about the delivery schedule and no stake in the delivery.

Why Demand Keeps Rising

Every new regulatory regime, security framework, and procurement questionnaire adds work to the maintainer's plate: bills of materials, disclosure policies, signed releases, attestations, long-term support commitments. The obligations flow downstream to volunteers. The budget that funds compliance stays upstream with the vendors.

Assessing Project Health Honestly

Star count is a popularity metric collected mostly from people who never used the software. It correlates with marketing, not with whether anyone will answer a security report next spring. These are the signals that tell you something.

Number of Active Maintainers

Not contributors -- maintainers. Count who merged a pull request or cut a release in the last twelve months. One is a risk. Two at the same employer is effectively one, because a single reorganisation removes both.

Release Cadence and Its Shape

A stable, finished library releasing once a year is healthy. An actively developed framework releasing once a year is stalling. What matters is the trend against the project's own history: cadence that halves and halves again is the clearest early warning of fatigue.

Issue and Security Response

Read the last twenty closed issues, not the count. Are they closed with an answer or by a stale bot? Does the project publish a security policy with a contact route, and has it ever issued an advisory? A project that has handled a disclosure calmly has demonstrated a capability that one with no security history has not.

Governance and Succession

Is there a written governance document? Is the project under a foundation, a company, or a personal account? Who can add a maintainer, and by what process? Who holds the signing keys and registry credentials? A project with a documented path for adding and removing maintainers can survive losing one. A personal account cannot, and cannot be transferred if its owner disappears.

Funding and Employment Status

Is anyone paid for this work? Corporate employment, a foundation grant, sponsorship, or nothing at all? Funded does not mean safe -- corporate funding vanishes when the sponsoring team is reorganised -- but it tells you whether maintenance competes with a day job. Unfunded plus single-maintainer plus load-bearing is the combination worth escalating.

Licence and Release Integrity

Confirm the licence is what you think it is and has not changed between major versions. Check whether releases are reproducible from the tagged source, whether artifacts are signed, and whether the published package matches the repository. As xz-utils demonstrated, an artifact you cannot reproduce from source is not something you can audit, whatever the source looks like.

When a Dependency is Abandoned

This is not an edge case. Black Duck's audit round reports that "93% of codebases contain components with no development activity in the last two years". Most organizations already carry dormant dependencies; they simply have not looked.

There are four honest responses and one dishonest one. The dishonest one is deciding nothing, which is what usually happens, and it converts a manageable decision into an emergency two years later when a vulnerability lands in code nobody owns.

Fork

You take over maintenance in public, as a community successor. Choose this when the package is widely used, the code is sound, and you are prepared to accept issues from strangers. Forking is a commitment to other people's problems, not only your own.

Best when: the library is strategic and others will help carry it

Vendor

You copy the code into your repository, record where it came from and at which commit, and maintain it as internal code. No public obligations and no release process. The cost is that you own every future fix, and the provenance note is all that stops the next engineer assuming it is homegrown.

Best when: you use a small part of a small library

Replace

You migrate to a maintained alternative, or to a platform capability that did not exist when the dependency was chosen. Often cheapest in the long run and most expensive this quarter, which is why it loses arguments it should win. Wrap the dependency behind your own interface first so the migration stays contained.

Best when: a healthy equivalent exists and the surface is narrow

Contribute

The project is not dead, only under-resourced. You send patches, help triage, or fund a maintainer, and the package stays alive without you owning it. Usually the highest-leverage option available and almost never the one proposed, because it requires admitting your company benefits from labour it does not pay for.

Best when: the maintainer is responsive but overloaded

Whichever you pick, write it down as an architectural decision with an owner and a date. An abandoned dependency handled deliberately is a managed risk. The same dependency handled by silence turns up in a postmortem with the phrase "nobody realised" in the timeline.

The Debt You Carry if You Publish

Open sourcing an internal library is a two-hour task and a multi-year liability. The moment somebody else depends on your package, you have taken on obligations no sprint plan accounts for.

Issue Backlog

An untriaged backlog is not neutral. It publicly signals that reports go unread, which suppresses the good ones and buries the important one among duplicates. Triage is far cheaper than fixing: an acknowledged issue with an honest "not planned" costs minutes and preserves the channel you will need when a genuine security report arrives.

Unreleased Fixes

A bug fixed on the main branch and never released is worse than an unfixed bug, because the issue gets closed and the world still ships the broken version. Downstream consumers either run known-broken code or pin to a git commit, which quietly disables their own dependency tooling. If you fix it, cut a release.

Breaking-Change Communication

Semantic Versioning is explicit: increment the major version "when you make incompatible API changes" and the patch version "when you make backward compatible bug fixes". That contract is only worth something if you honour it. A behaviour change shipped in a patch release costs every consumer a debugging session and teaches them to stop trusting your version numbers.

Succession Planning

Who takes over when the one engineer who cares about this package changes teams? Publishing rights, signing keys, and repository ownership should be held by the organization and documented, not by whoever happened to run the first release command. Succession is the difference between a project that changes hands and one that goes dark.

An Honest End of Life

Archiving a project is a legitimate, responsible act. Say clearly that it is unmaintained, mark it archived in the registry, point at a successor if one exists, and stop. Ambiguity is the harm: a repository that looks alive because a bot bumps its dependencies keeps attracting users who believe somebody is watching.

Account and Key Hygiene

Your publishing credentials are a supply chain control for everyone downstream. Enforce multi-factor authentication, use short-lived scoped tokens from CI rather than a personal token in an environment variable, and require review before a release can be published. This belongs in your governance policy, not in one engineer's habits.

Funding Models: What They Fix and What They Do Not

Money is the obvious answer to unpaid labour, and it does help. It is worth being precise about what it buys, because a sponsorship line item is often treated as though it discharged the risk. It does not.

What Funding Does Solve

It removes the choice between the project and paid work, which is what actually drives most maintainers away. It buys time for the unglamorous work nobody volunteers for: releases, documentation, CI upkeep, deprecation cycles. Recurring corporate sponsorship, foundation grants, dual licensing, paid support contracts, and commercially maintained distributions all deliver this, in roughly ascending order of reliability.

What Funding Does Not Solve

It does not create a second maintainer, and concentration is the actual risk. It does not distribute knowledge, transfer signing keys, or build a review culture. It rarely reaches the transitive dependencies you never chose. And unless it is contractual it creates no obligation: a sponsored maintainer can still stop tomorrow, and a sponsoring company can still cancel next quarter.

The useful model is that funding buys capacity while governance buys continuity, and only one of them substitutes for luck. If a package is load-bearing for your business, the question to ask is not only "can we sponsor you" but "can we help you add a second maintainer, and what would that take". The second question is the one that changes your risk profile.

Contributing Upstream is the Cheapest Risk Reduction Available

Most organizations already carry a private patch or two against an upstream package. They were written under deadline, they live in a build script or a fork nobody wants to discuss, and every upgrade re-applies them by hand. That is a permanent tax paid to avoid a one-time conversation.

Upstreaming them costs a review cycle and removes the tax forever. It also does something a purchase order cannot: it puts one of your engineers inside the project. They learn the code, they build standing with the maintainer, and if the project ever needs a successor your organization is a plausible one rather than a stranger asking for keys.

Start With Triage

Reproducing bug reports, writing failing tests, and closing duplicates is the work maintainers most want help with and volunteers least want to do. It needs no commit access and demonstrates seriousness faster than a large unsolicited pull request.

Make It Sanctioned Work

Contribution done on evenings and weekends is a hobby that stops when the engineer gets busy. Put upstream time on the roadmap with a named owner and a budget in hours, and treat the resulting relationship as an asset the organization owns.

Report Responsibly

When you find a security flaw in a dependency, use the project's disclosure route, allow reasonable time, and offer a patch. An unpaid maintainer handed a deadline and no help is how a fix gets rushed. See security and supply chain debt for the wider programme.

Related Resources

Frequently Asked Questions

Count the people who merged a pull request or cut a release in the last twelve months, and check whether they are independent or all at one employer. Then look at release cadence against the project's own history, read the last twenty closed issues to see whether they were answered or bot-closed, and find out whether anyone is paid for the work. Unfunded, single-maintainer, and load-bearing for your business is the combination to escalate. Star count tells you about marketing, not about who will answer a security report.

An account using the name Jia Tan began contributing to xz-utils in October 2021 with innocuous patches, was named alongside Lasse Collin as a project maintainer in the README by November 2022, and was merging commits directly by the end of that year. Alongside this, sockpuppet accounts pressured the original maintainer about the slow release pace while he was publicly describing long-term health difficulties and an unpaid hobby project. Malicious code was later found in the distributed tarballs of versions 5.6.0 and 5.6.1, tracked as CVE-2024-3094 and disclosed by Andres Freund on 29 March 2024. No scanner would have caught it; the attack targeted a person's capacity, not a code defect.

Fork when the package is strategic and others will help carry it, accepting that you inherit other people's issues. Vendor when you use a small part of a small library and want no public obligations, recording the origin commit so nobody later mistakes it for homegrown code. Replace when a healthy equivalent exists and the integration surface is narrow. Contribute when the maintainer is responsive but overloaded, which is usually the highest-leverage option and the one least often proposed. The wrong answer is deciding nothing, which converts a manageable choice into an emergency later.

Partly, and less than most sponsors assume. Funding removes the forced choice between the project and paid work, and it buys time for releases, documentation, and deprecation cycles nobody volunteers for. What it does not do is create a second maintainer, distribute knowledge, transfer signing keys, or reach the transitive dependencies you never chose. Unless it is contractual it creates no obligation either. Funding buys capacity; governance buys continuity. If a package is load-bearing, ask what it would take to add a second maintainer, not only what it would take to sponsor the first.

Triage, releases, honest versioning, and a clear signal about the project's status. Triage matters more than fixing: an acknowledged issue with a plain "not planned" preserves the channel you will need when a real security report arrives. Fixes that sit unreleased on the main branch are worse than open bugs, because the issue gets closed while the world still ships the broken version. And if you stop maintaining it, say so explicitly and archive it, because ambiguity keeps attracting users who believe somebody is watching.

It is technical debt with the same structure as any other kind: a decision taken for short-term speed, carrying interest that accrues quietly until something forces repayment. Adopting a package saved weeks of work, and the interest is the ongoing obligation to track its health. What makes maintainer debt distinctive is that the interest accrues on someone else's ledger until the day it transfers to yours, which is why it stays invisible to tooling that only inspects your own repository. It belongs in the same register, with the same owners and review cadence, as the debt you wrote yourself.

Know Who Maintains What You Ship

Pick your ten most load-bearing dependencies and answer one question for each: how many people could cut an emergency release tomorrow? The answers are usually worse than expected, and they are always actionable.