Safeguard
Supply Chain Security•

Is Battle-Tested Open Source Code Actually Safe After AI Bug Finds?

Not by age alone. Mature code hides old bugs that AI now finds fast. Judge libraries on maintainers, fuzzing, memory safety and fix speed, then patch.

Safeguard Security Team
37 min read

No. "Battle-tested" means a library has run in production for years without failing in ways people noticed, which is not the same as having no exploitable bugs. Mature open source still carries old flaws, and AI tools now find them quickly. Judge core dependencies on maintenance, fuzzing, memory safety and fix speed, and budget to patch them.

The question is loud this week for a reason. On 21 October 2026 the PHP project shipped fixes for two critical remote code execution flaws that, according to its advisory, affect every PHP installation serving web requests. Researchers found them with the help of AI models. Fortune's reporting puts the core bug's age at about 14 years, and says the researchers did not expect to find anything critical in code that had been examined for so long. The FBI and NSA told organisations to update immediately or take affected systems offline. That is a hard thing to hear about a runtime that powers a large share of the web and has been "battle-tested" for decades.

This post answers the broader question for engineering managers, architects and AppSec leads: what maturity really buys you, what predicts vulnerabilities better than age, and how to plan for AI-driven discovery reaching your most trusted code. For the incident itself, see our explainer on the PHP flaws and our post on what AI-found bugs mean for defenders.

Key takeaways

  • "Battle-tested" measures survival under normal use. It does not measure how well the code holds up against a patient adversary feeding it unusual input.
  • Long-lived bugs are normal, not exceptional. A USENIX Security 2022 study estimated the average vulnerability lifetime at about 4 years, with OpenSSL near 7 years. Heartbleed sat in OpenSSL for about two years in code that the whole internet depended on.
  • Fuzzing and coverage help but do not finish the job. Google and Anthropic have both published bugs that heavily fuzzed code still hid.
  • AI changes the economics. Anthropic says its Frontier Red Team found and validated more than 500 high severity vulnerabilities in open source projects, some undetected for decades. Expect more advisories against mature code, often in clusters.
  • Newer code is not automatically riskier or safer. Bugs concentrate in new code, but small new projects add other risks such as a single maintainer.
  • Better signals than age: maintainer diversity, security releases for older branches, fuzzing enrollment, memory safety of the code that parses untrusted input, code review, and a track record of fixing advisories quickly.
  • Plan capacity, not heroics. Tier dependencies, set patch SLAs by exploitation and reachability, stay on supported branches, and automate the upgrade work so a cluster of fixes in old code does not stall the team.
  • For a boundary component you cannot keep current, a hardened or maintained build is often cheaper than one emergency.

What does "battle-tested" actually measure, and what does it not?

People use "battle-tested" to mean several different things at once. It helps to pull them apart, because each one is real evidence of something, just not of security.

Uptime and production use. A library that has run for ten years in thousands of applications has had its common paths exercised far more than any test suite could. Crashes on ordinary input get found and fixed. But production traffic is mostly benign and repetitive. It exercises the paths users take, not the ones an attacker constructs.

Download counts and popularity. High usage means visible failures get noticed. It also means a single bug has a huge blast radius. Popularity tells you how bad a flaw would be, not how likely one is.

Fuzzing history. A project enrolled in continuous fuzzing has had enormous amounts of machine generated input thrown at it. Fuzzing is good at shallow memory bugs reachable from the entry points its harnesses cover. It is weaker on bugs that need long sequences of specific operations, unusual build flags or configuration, or state that persists across requests. Anthropic's write up gives a concrete example from the CGIF library: a logic flaw tied to LZW compression that needs a specific sequence of operations, which the team suggests might not be caught even with 100% line and branch coverage.

Audits. A security audit is a time boxed review of a defined scope. It is a snapshot, and code changes after it. We cover how to read audit claims in has this open source library been security audited.

Absence of known CVEs. A clean record can mean sound code, that nobody skilled has looked hard, or that fixes ship quietly without advisories. A scanner cannot tell these apart.

Signal people call "battle-tested"What it is good evidence forWhat it does not tell you
Years in productionCommon paths work; ordinary input is handledBehaviour under crafted, hostile input
High download countsVisible failures get noticed; large communityLikelihood of a hidden flaw; it raises blast radius instead
Continuous fuzzingShallow memory bugs on harnessed paths are rarerDeep state, configuration specific and multi step bugs
Past security auditNamed reviewers checked a defined scope at a point in timeCode written after the audit, or outside its scope
Few or no CVEsPossibly sound codeWhether anyone skilled has looked, or whether fixes are disclosed

The honest summary: maturity reduces the density of easy bugs. It does nothing about the bugs that are hard to reach, and it can make teams stop looking for them.

Why do long-lived bugs survive in mature code?

The research record here is consistent. Old code keeps old bugs for structural reasons, and most of those reasons apply to the dependencies you rely on most.

Bugs live for years on average

The USENIX Security 2022 paper "How Long Do Vulnerabilities Live in the Code?" by Alexopoulos and colleagues estimated that the average lifetime of a vulnerability is around 4 years, with wide variation by project: about 2 years for Chromium and about 7 years for OpenSSL. The authors also found that lifetimes of vulnerabilities fixed in a given year have been rising along with overall code age. So a mature project with a slow moving core is exactly where you should expect bugs that have been present for a long time.

Heartbleed is the classic case. According to the project's disclosure site, the bug was introduced in December 2011, shipped in OpenSSL 1.0.1 in March 2012 and was made public on 7 April 2014, fixed in 1.0.1g. That is about two years in the most scrutinised cryptographic library on the internet. Log4Shell is another: CISA lists the affected Apache Log4j range as 2.0-beta9 through 2.14.1, which means the flawed lookup behaviour shipped across the entire 2.x line for years before it became the emergency of December 2021.

Legacy code paths get the least attention

Mature projects accumulate features that few people use: old protocol options, compatibility modes, rarely enabled extensions, error handling for conditions that almost never occur. Those paths are reachable, because they ship, but they get little review and little test traffic. The PHP flaws are an example of this shape. PHP's advisory describes one issue as out of memory handling that can interrupt the runtime while request data is only partly initialised, and the other as request owned state that can survive after its memory is freed and be used by a later request on the same worker. Neither is a path that normal traffic or normal tests exercise.

Memory unsafe languages turn small mistakes into code execution

Much of the infrastructure people call battle-tested is C or C++: runtimes, TLS libraries, parsers, compression libraries, database engines. There, a missing bounds check or a use after free can become remote code execution rather than a crash. CISA's guidance on memory safe roadmaps exists because this class of bug keeps recurring, and Google reported that memory safety issues made up 76% of Android vulnerabilities in 2019 and 24% in 2024, after it started writing new code in memory safe languages (as summarised by Help Net Security). Language choice does not make code correct, but it changes how bad a mistake can be. See our post on the CISA memory safe languages roadmap for the policy side.

Coverage is not correctness

Teams often read a high coverage number as "tested". Two published examples show why that is not enough. Google's Project Zero described how its Big Sleep agent found an exploitable stack buffer underflow in SQLite in October 2024. Google's OSS-Fuzz team separately reported that AI generated fuzz targets found 26 new vulnerabilities, including one in OpenSSL that Google said had likely been present for about two decades and would not have been discoverable with existing human written fuzz targets (as reported by The Hacker News). The same report notes Google's point that line coverage does not prove a function is free of bugs, because different flags and configurations trigger different behaviour.

Fuzzing has not shortened bug lifetimes as much as hoped

This one surprises people. The USENIX study found that the introduction of fuzzers did not significantly reduce the lifetimes of memory related vulnerabilities in the projects it examined. The authors call for more research, and fuzzing clearly finds a great deal. But it is evidence that "this project is fuzzed" should raise your confidence a little, not settle the question.

Few maintainers carry very old, very central code

Many foundational packages are maintained by a handful of people, often volunteers. The Census II study from the Linux Foundation and Harvard's Laboratory for Innovation Science set out to identify the most widely used open source packages so that security resources could be directed to them. Anthropic notes that many maintainers receiving its reports are volunteers with few security resources. A small team can keep a mature project stable; it usually cannot also review every legacy path adversarially.

What changes now that AI tools find bugs in old code quickly?

Two things change at once: the cost of looking drops, and the number of findings in mature code rises.

For defenders

The AI labs have published their own results. Anthropic's Frontier Red Team wrote on 5 February 2026 that, using Claude Opus 4.6 in a virtual machine with standard tools such as debuggers and fuzzers and no special harness, it found and validated more than 500 high severity vulnerabilities in open source software. It named GhostScript, OpenSC and CGIF as examples and said some bugs in well tested projects with millions of hours of accumulated fuzzing had gone undetected for decades. In the GhostScript case, the model found the bug by reading the commit history and noticing another caller missing the same bounds check. Anthropic says the team validated findings and wrote patches by hand at first, then brought in external researchers as volume grew, specifically to keep false positives away from maintainers.

Google's Project Zero framed its Big Sleep result as an "asymmetric advantage for defenders" when bugs are found before they ship, while stressing that the results were highly experimental. The SQLite bug it described was fixed the same day it was reported and never reached an official release.

For a team that consumes open source, the upside is real but indirect. You benefit when these tools run upstream and bugs are fixed before release. You do not get immunity: the fixes still arrive as advisories and new versions you must deploy.

For attackers

The same capability works for the other side. Anthropic acknowledges the dual use risk and says models may soon exceed the speed and scale of expert human researchers. The practical effects for consumers of open source are:

  • The gap between disclosure and exploitation shrinks. Once a fix is public, the diff points at the bug. Tools that reason about code can turn a patch into a working understanding of the flaw faster than before.
  • Old, unpatched branches become more attractive. If a bug has been present for 14 years, every version in that range is affected, including end of life lines that will never get an official fix. PHP's advisory notes that 8.1 and older no longer receive updates from the project, though it published minimal source backports for 7.4, 8.0 and 8.1 this time.
  • Leaks hurt more. The PHP disclosure leaked before the planned release. When discovery is cheaper, more people know about a bug before the fix.

For maintainers, and therefore for you

Anthropic says standard 90 day disclosure windows may not keep pace with the volume of AI discovered bugs. More valid reports mean more frequent security releases and backports, and that lands in your backlog. We look at the maintainer side in how to handle a flood of AI generated vulnerability reports and the consumer side in AI is finding vulnerabilities faster than we can patch.

Are newer, smaller libraries riskier or safer than old, popular ones?

Neither, as a rule. They carry different risks, and the evidence cuts against the simple story that old means safe.

The case that new code carries more bugs

Both the USENIX study and Google's Android work point the same way: vulnerabilities concentrate in new or recently modified code. Google used this to explain why its Android vulnerability counts fell even while the amount of memory unsafe code grew. It wrote new code in memory safe languages, left most existing C and C++ in place, and older code kept getting safer as bugs were found and fixed. So a young library, especially one changing fast, is likely to have a higher density of undiscovered bugs per line than a stable old one.

The case that old code is not as safe as it looks

Old code still holds bugs that live for years, and AI driven review is now finding them in batches. A popular library also has a larger blast radius, which draws attackers and makes your rollout harder.

The risks that are specific to small and new projects

Small projects add risks that have nothing to do with code age. A single maintainer can lose interest, change jobs or lose an account. There may be no security policy, no release process for older versions and no one to answer a report. The OpenSSF Concise Guide for Evaluating Open Source Software lists these directly: look for significant activity in the last 12 months, more than one maintainer ideally from different organisations, a release in the last 12 months, and a clear way to report vulnerabilities. We go deeper on this in immature open source projects as a supply chain risk.

FactorOld, popular libraryNew, small library
Density of undiscovered bugs per lineUsually lower in stable core codeUsually higher, especially if changing fast
Long-lived hidden bugs in legacy pathsCommon; now being found by AI reviewFewer legacy paths, but less history to judge
Blast radius when a bug is foundVery large; attackers pay attentionSmaller, unless it sits in a popular dependency tree
Maintainer depthOften several, sometimes still thin for its importanceOften one person
Security process (policy, backports, advisories)Usually presentOften missing
Patch effort for youHigh: it is everywhere in your estateLow to moderate, but may need replacement if abandoned
Best responseTrack advisories, stay on supported branches, patch fastCheck maintenance signals, limit to non critical paths, have an exit plan

The useful question is not "old or new" but how the project behaves when a bug is found, and how exposed you are.

Which signals predict future vulnerabilities better than age?

No single metric predicts vulnerabilities reliably, and you should be wary of anyone who claims one does. What you can do is combine a few signals that track how likely bugs are to exist, how quickly they get fixed, and how much damage they can do to you. The OpenSSF Concise Guide and the OpenSSF Scorecard checks are good public baselines; the table below groups them by what they actually tell you.

SignalWhy it mattersWhere to check it
Maintainer count and organisational diversityMore reviewers, less key person risk, more capacity to respondRepository contributors; Scorecard "Contributors" (at least 3 companies, each with at least 5 of the last 30 commits)
Recent activity and release cadenceA project with no commits or releases in 12 months may not ship your fixScorecard "Maintained" (full marks need at least one commit per week over 90 days); registry release history
Security releases for older branchesDetermines whether you can patch without a major upgradeProject security policy, release notes, LTS statements
Code review on changesUnreviewed changes are where new bugs enterScorecard "Code-Review"
Fuzzing enrollmentShallow memory bugs get found continuouslyScorecard "Fuzzing" (OSS-Fuzz, ClusterFuzzLite, or language native fuzz tests)
Memory safety of the parsing codeDecides whether a bug is a crash or code executionLanguage of the modules that handle untrusted input
Attack surfaceParsers, protocol handlers and request processing see hostile inputYour own architecture: what the component touches
Advisory history and time to fixPast behaviour is the best predictor of future responseAdvisory databases, release dates versus report dates
Security policy and reporting channelResearchers can reach the maintainers privatelyScorecard "Security-Policy"; a SECURITY.md file
Exposure in your applicationWhether the vulnerable code is reachable from your codeReachability analysis in your SCA tooling

A few notes on reading these honestly.

Scorecard is a hygiene check, not a vulnerability forecast. The checks measure practices such as branch protection, pinned dependencies and token permissions. They correlate with a project that runs a careful process. They do not inspect the code for bugs. Scorecard's own documentation notes, for example, that the Dependency-Update-Tool check confirms a tool is enabled but not that updates are merged, and that Signed-Releases does not verify the signatures.

Advisory history is double edged. Many advisories may mean a well studied, responsive project. A long list of quickly fixed advisories is a better sign than a short list of slowly fixed ones.

Memory safety and attack surface multiply each other. A C library that only processes trusted configuration at startup is a different risk from a C library that parses every inbound request. Weight your concern by where the component sits.

Your exposure matters more than the project's average. The same advisory can be critical for one application and irrelevant for another, depending on whether the vulnerable function is called. Reachability analysis is the most direct way to turn a project level risk into your risk. We explain the difference between function level and package level analysis in this guide.

Gold Open Source is a free place to pull several of these signals together for a package before you adopt it: package pages show versions, known vulnerability counts, license, download counts and OpenSSF Scorecard health, and CVE pages show affected and fixed versions with CVSS, EPSS and CISA KEV status. It needs no login.

Step by step: assess a core dependency in about 30 minutes

Use this when you are choosing between libraries, reviewing a component that sits on a trust boundary, or deciding whether to keep a long-standing dependency. Replace the example names with your own.

1. Confirm what you actually run

Start with your inventory, not the project's README. You need the exact versions in every application, including transitive copies.

# npm: every copy of a package in the tree, with the path that pulls it in
npm ls lodash --all

# Python: installed version and what requires it
pip show requests
pipdeptree -r -p requests

# Maven: where a library enters the dependency tree
mvn dependency:tree -Dincludes=org.apache.logging.log4j

# Go: module versions in the build
go list -m all | grep golang.org/x/net

# Container image: the runtime inside the image, not on the host
docker run --rm my-app:latest php -v

With Safeguard, safeguard scan --dir ., safeguard scan --image my-app:latest and safeguard scan --sbom sbom.json produce the same inventory and write JSON results under ./output. The platform then shows which projects contain a given component and version, which is the question you will be asked the day a critical advisory lands.

2. Check the project's maintenance signals

# OpenSSF Scorecard results for a GitHub repository (public API)
curl -s https://api.securityscorecards.dev/projects/github.com/expressjs/express \
  | jq '{score, checks: [.checks[] | {name, score}]}'

# Or run Scorecard yourself (needs a GitHub token in GITHUB_AUTH_TOKEN)
scorecard --repo=github.com/expressjs/express --checks=Maintained,Code-Review,Fuzzing,Security-Policy,Contributors

# npm: maintainers and recent release dates
npm view express maintainers
npm view express time --json | jq 'to_entries | sort_by(.value) | .[-5:]'

# PyPI: release history size and latest version
curl -s https://pypi.org/pypi/requests/json | jq '{latest: .info.version, releases: (.releases | keys | length)}'

# deps.dev: versions and advisories known for a package
curl -s https://api.deps.dev/v3/systems/npm/packages/express | jq '.versions | length'

3. Look at the repository directly

A shallow clone is enough for most of this.

git clone --filter=blob:none https://github.com/OWNER/REPO.git && cd REPO

# Who actually commits, over the last year
git shortlog -sne --since="12 months ago" | head -20

# How much activity in the last year
git log --since="12 months ago" --oneline | wc -l

# Security fixes in the last three years
git log -E --grep="CVE-|[Ss]ecurity" --since="3 years ago" --oneline | head -30

# How much of the code is C or C++
git ls-files | grep -Ec '\.(c|h|cc|cpp|hpp)$'

# Is there a security policy?
ls SECURITY.md .github/SECURITY.md 2>/dev/null

To check whether a project is enrolled in OSS-Fuzz, look for its directory in the OSS-Fuzz repository:

curl -s -o /dev/null -w "%{http_code}\n" \
  https://raw.githubusercontent.com/google/oss-fuzz/master/projects/REPO/project.yaml
# 200 means a project definition exists under that name

4. Read the advisory history and time to fix

# Known vulnerabilities in your lockfiles, from the OSV database
osv-scanner scan source -r .

# Go: only the vulnerabilities your code actually calls
govulncheck ./...

# A single CVE from Gold Open Source's free read API
curl -s https://gold.safeguard.sh/api/vulnerabilities/CVE-2021-44228 | jq .

For the three or four most recent advisories, compare the report date with the release date of the fix and check whether older supported branches got the fix too. That gap is the best evidence you will get about how the next bug will be handled.

5. Map where the component sits

Write down, in one sentence each: does it parse untrusted input, does it handle authentication or cryptography, does it run in a request path, and does it run with elevated privileges. A yes to any of these moves it into your top tier.

6. Decide and record

Record the decision in your dependency policy: tier, owner, supported branch you will stay on, patch SLA, and what you will do if the project stalls. Then put a gate in CI so the decision holds:

# .github/workflows/dependency-gate.yml
name: dependency-gate
on: [pull_request]
jobs:
  gold-scan:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: safeguard-sh/gold-scan-action@v1
        with:
          fail-on: kev

Start with fail-on: kev, which fails only on known exploited vulnerabilities, and move to vuln once your backlog is under control.

What should you expect in your backlog next year?

Nobody can give you a reliable number, and you should distrust forecasts that pretend to. What the published evidence supports is a direction and a shape.

More advisories against mature, central code. Anthropic, Google and independent researchers are all pointing AI assisted review at widely used open source, and they are reporting long-lived bugs in code that was considered well tested. Expect advisories in components you have not had to think about for years: language runtimes, image and document parsers, compression and serialisation libraries, TLS and crypto code, database engines.

Clusters, not a steady trickle. When a tool or a team finds a new bug class in a project, it often finds siblings. Anthropic's GhostScript example came from noticing one fix and finding another caller with the same missing check. Expect some releases to fix several issues at once, and expect follow-up releases after the first fix as researchers look at the patched area.

Fixes that span many versions. A bug that has existed for a decade affects every version in that range. Projects will backport to supported branches; end of life branches will mostly not get official fixes. If you run old branches, more of your backlog will be "upgrade a major version" rather than "bump a patch release". PHP's advisory notes that 8.2 reaches end of life on 31 December 2026, for example.

Less time between disclosure and exploitation. If the tools that find bugs can also explain them, the useful life of an unpatched system after disclosure gets shorter. Plan your SLAs around that.

More noise, too. Not every valid advisory affects your code. Triage on four questions: is it known exploited, is it likely to be exploited, is the vulnerable code reachable, and is the system exposed. FIRST's EPSS scores, published daily for every CVE, estimate the probability of exploitation in the next 30 days; CISA's KEV list confirms exploitation that has happened. Our CVSS, EPSS and KEV explainer covers how to combine them.

How do you plan patch capacity for a rising volume of fixes in old dependencies?

Tier your dependencies

Not every dependency deserves the same SLA. A simple three tier model works for most teams.

TierWhat belongs herePatch SLA for a critical or known exploited issuePatch SLA for others
Tier 1: boundaryRuntimes, web servers, parsers of untrusted input, auth and crypto libraries, anything in the request pathHours to 2 days, with an offline or isolation plan if you cannot meet itNext regular release, within 2 to 4 weeks
Tier 2: application coreFrameworks and libraries your code calls directly but that do not face raw input7 days if reachable, next release if notBatched monthly
Tier 3: tooling and build timeTest frameworks, linters, build plugins, dev only packagesNext scheduled update, unless it runs in CI with secretsBatched quarterly

The FBI and NSA advice on the PHP flaws is a reminder that for Tier 1 the fallback is not "wait". It is to take the system offline or isolate it until it can be updated. Our post on whether to take a system offline if you cannot patch covers that decision in depth.

Measure your input and your throughput

Count, per month and per tier, how many new advisories match your estate and how many you close. If input exceeds throughput for two months running, the backlog grows regardless of effort, and you need more automation, fewer dependencies, or a different supply of fixes.

An illustrative calculation, with numbers you should replace with your own: if your estate has 40 services and you see on average 30 new matching advisories a month, of which reachability and exposure filtering leave 8 that need action, and each upgrade costs a developer half a day including testing and review, that is 4 developer days a month in steady state. A cluster month with three times the input is 12 days. If you only have 4 days budgeted, the cluster month becomes a two month backlog. Budget for the cluster, not the average.

Reduce the work per fix

  • Stay close to current. Upgrading from one patch release to the next is cheap. Jumping two major versions under pressure is not. A regular update cadence for Tier 1 and Tier 2 keeps emergency fixes small.
  • Stay on supported branches. Track end of life dates for runtimes and core libraries and plan migrations a release ahead. Every service on an end of life branch turns a routine patch into a migration project.
  • Rebuild, do not just upgrade the host. Runtimes bundled inside container images are not fixed by updating the host. Rebuild images on a fixed base and redeploy.
  • Automate the upgrade itself. Dependency update bots that open pull requests are the baseline. Autonomous remediation that opens tested, policy gated pull requests across many repositories at once is the step that keeps up with clusters.

Rehearse the emergency path

Pick a Tier 1 component and run a drill: find every service that uses it, upgrade, test, deploy, and time each step. The slowest step is usually the first, working out where the component lives. Our guide to SBOM driven incident response walks through it.

When is it worth paying for hardened or maintained builds of a core component?

Paying for a hardened or maintained build is a trade: you buy faster fixes, longer support for older branches, or a cleaner starting point, instead of doing that work yourself. It is worth considering when several of these are true.

SituationPay for hardened or maintained builds?Why
A Tier 1 component on a branch you cannot upgrade quicklyUsually yesBackports and patched builds let you fix without a migration under pressure
A component whose upstream has few maintainers and slow security releasesOften yesYou are paying for response capacity the project does not have
Container base images that rebuild frequently with many inherited CVEsOften yesA hardened base reduces the volume you triage every week
Regulated environments that need provenance and audit evidence per artifactOften yesSigned artifacts with provenance and evidence pages shorten audits
A well maintained library on a current branch with fast upstream fixesUsually noUpstream already gives you what you would buy
A dev only or build time toolRarelyLow exposure; standard updates are enough
You have no inventory of where the component runsNot yetFix inventory first, or you will not know where to deploy the hardened build

Two cautions. A hardened build still has to be rolled out across your estate like any upgrade. And ask the provider exactly what they guarantee: which branches, what time to fix, what happens when upstream has no fix, and what evidence you get. Safeguard's Gold Registry, described below, publishes its bar and an evidence page per artifact so you can check before you depend on it.

Common mistakes

  • Treating age as a security property. Age tells you the easy bugs are probably gone. It says nothing about the hard ones, and hard ones are what AI assisted review is now surfacing.
  • Reading popularity as review. Many users is not many reviewers. Most people who depend on a library never read its code.
  • Assuming "fuzzed" means "safe". Fuzzing finds what its harnesses reach under the configurations they are built with. The SQLite and OpenSSL examples above both slipped past existing harnesses.
  • Patching the host and forgetting the image. A runtime inside a container image keeps its old version until you rebuild and redeploy.
  • Running end of life branches because "it works". When a bug spans a decade of versions, end of life branches are where official fixes stop.
  • Treating every new advisory as equally urgent. Without exploitation data, reachability and exposure, a rising volume of findings becomes noise and the important ones wait in line.
  • Measuring effort instead of throughput. A team that works harder while the backlog grows needs a different input or a different supply of fixes, not more overtime.
  • Swapping an old library for a new one to "be safe". You may trade a well understood risk for a less visible one: a single maintainer and no security process.
  • No exit plan for critical dependencies. If a core project stalls, you need to know in advance whether you would fork, pay for maintenance, or replace it.

FAQ

Is old open source code safer than new code?

Per line, stable old code usually has fewer undiscovered bugs than fast changing new code; both Google's Android data and the USENIX Security 2022 study find vulnerabilities concentrating in new or recently modified code. But old code still holds bugs that survive for years, and its wide use makes each one more damaging. Age lowers the odds of easy bugs, not the odds of any bug.

Does "many eyes" make open source secure?

Only if the eyes look at the right code with the right skills. Heartbleed sat in OpenSSL for about two years, and Fortune reports the recent PHP bug was present for around 14. Open source makes review possible; it does not make it happen.

Can AI really find vulnerabilities in mature open source projects?

Yes, according to the labs' own published results. Anthropic reports finding and validating more than 500 high severity vulnerabilities in open source with Claude Opus 4.6, some undetected for decades in heavily fuzzed code. Google's Project Zero reported an exploitable SQLite bug found by its Big Sleep agent before release. Human validation was part of both workflows.

How do I check if an open source library is still maintained?

Look for commits and a release in the last 12 months, more than one active maintainer, a security policy, and recent security fixes that reached older branches. The OpenSSF Scorecard "Maintained" check and the OpenSSF Concise Guide give concrete thresholds. git shortlog -sne --since="12 months ago" shows who actually commits.

Is a high OpenSSF Scorecard score proof that a package is safe?

No. Scorecard measures practices such as code review, branch protection and fuzzing enrollment. It does not test the code for vulnerabilities. Use it alongside advisory history, attack surface and your own reachability results.

Will AI-found bugs mean more CVEs for my team to patch?

Most likely, and in clusters, with fixes that span many versions. Triage by known exploitation, EPSS, reachability and exposure, and automate the upgrades that remain.

When should we pay for a hardened or supported build?

When a critical boundary component cannot be upgraded quickly and upstream response is slow or has ended. You buy backports, faster fixes and audit evidence. It is rarely worth it for dev only tools or libraries you already keep current.

What should we do the day a critical bug lands in a core library?

Find every place it runs, including inside container images. Check whether it is exposed and reachable. Apply the fixed version or your distribution's backport, rebuild and redeploy images, and if you cannot patch a Tier 1 system quickly, isolate it or take it offline. Then check for signs of compromise, because patching does not remove an attacker who got in first.

Fix it without waiting for upstream

The point of this post is that mature code will keep producing serious fixes, often for versions you thought were settled. When that happens, the gap that hurts is between the fix existing and the fix running in your builds, or worse, the period before any fix exists for the branch you are on.

Whatever the vulnerability, most of the risk sits in two gaps. The first is the time between a fix being published and that fix actually running in your production builds. The second, and worse, is the time before any fix exists at all, while a maintainer works out a patch and a release schedule. Waiting through both gaps is a habit, not a requirement. Safeguard gives teams three ways to close them.

1. Autonomous remediation: pull requests, not tickets

When a fixed version exists, Safeguard's Griffin models open a tested, policy gated pull request that moves the affected dependency to the safe version. You can run it on one repository or in bulk across every project that carries the vulnerable version. Remediation covers eight categories, including dependencies, licenses, security posture and findings. Reachability analysis ranks the vulnerable code paths your application actually calls first, so the first pull requests you merge are the ones that matter most. Autonomous remediation ships switched off, with every category set to Manual, so your team decides how much runs on its own and what still needs a human approval.

2. Gold Open Source: the safe version in seconds, free

gold.safeguard.sh is free and needs no login. Search any CVE or package to see affected and fixed versions, CVSS, EPSS, CISA KEV status and a recommended safe version, or use the "Am I affected?" checker. The same data is available through a free read API, README status badges and RSS threat feeds. The safeguard-sh/gold-scan-action GitHub Action can fail a build on a known exploited vulnerability, on any known vulnerability, or never, so a version you have just removed cannot quietly come back in next week's merge.

3. Gold Registry: start from components that are already fixed

registry.safeguard.sh provides hardened, drop in replacements for upstream packages and container images. Every Gold artifact is held continuously to zero exploitable critical or high CVEs, zero malware and a completed license check, with SLSA L3 or higher provenance, a Sigstore signature and a public evidence page you can hand to an auditor. An artifact loses its Gold badge if it regresses. Teams can point their own package directory at the registry so hardened equivalents resolve without changing how developers install anything.

When upstream has no fix yet, or will not ship one, Safeguard first works to get the fix accepted upstream. If the issue is severe or upstream will not move, Safeguard builds a fork, fixes the vulnerability there and publishes a hardened Gold build, so you are not stuck on a maintainer's release schedule. You can also request a hardened, compatibility tested build of a specific package. This fork and patch flow is in early access today, so ask which packages it covers before you plan around it.

Your situationWhat to use
A fixed version existsAutonomous remediation opens the upgrade pull request; Gold Open Source confirms the safe version
You need to know today whether you are affectedGold Open Source lookup and "Am I affected?" checker, free and without login
You want vulnerable versions to stop shippingThe Gold scan GitHub Action in CI, plus Safeguard policies and gates
Upstream has no fix yet, or will not ship oneA custom Gold request; fork and patch (early access)
You want to start clean on new projectsPull hardened components and images from Gold Registry

One honest limit: when the vulnerable code lives in a vendor appliance, a hosted service or an operating system runtime you do not build yourself, the fix still has to come from that vendor or distribution. The steps above apply to the open source dependencies and container images you build and ship, which is where most teams carry the largest and least tracked share of their exposure.

See how Safeguard would help

The first demo is a real Safeguard CLI session. After installing it, running safeguard opens the interactive terminal, and the user asks it to fix the lodash CVE in a repository. It reads the finding and the advisory, asks before each command, edits package.json to lodash 4.17.21, runs npm install and npm test with approval, prints a summary and pushes nothing. It then shows /permissions, /model and /scan . The same flow applies when an advisory lands in any long-lived library you depend on: the upgrade is proposed, tested and left for your review.

Click through it at your own pace, or open it full screen.

The second demo sets up the Safeguard runner on your own machine, approves it with its device code, and then scans from the terminal. This is the step that answers "where do we run this component" for code and images you build locally, before a cluster of fixes arrives rather than during one.

Click through it at your own pace, or open it full screen.

The third demo connects Claude to the Safeguard MCP server with OAuth and chooses which tools Claude can use. Once connected, an architect weighing whether to keep a core dependency can ask about projects and the vulnerabilities affecting them in plain language, with access limited to the tools you allowed.

Click through it at your own pace, or open it full screen.

To try it on your own code, download Safeguard at safeguard.sh/download and follow the CLI documentation.

Quick check

A library has run in production for ten years, is fuzzed continuously and has no open CVEs. Is it safe to treat as low risk?

No. Those facts lower the odds of easy bugs, but long-lived bugs in mature, fuzzed code are well documented, from Heartbleed to the findings Anthropic and Google have published. Judge it by where it sits in your system, its memory safety, its maintainers and how fast it fixes advisories, and keep it on a supported branch with a patch SLA.

Your team sees three times the usual number of advisories in one month after a wave of AI-assisted findings. What should change first?

Triage and automation, not effort. Filter by known exploitation, EPSS, reachability and exposure so only the advisories that affect your code reach a developer, then let automated pull requests handle the upgrades. Budget patch capacity for cluster months, not the average month.

Sources

Last reviewed: 23 October 2026. AI-assisted vulnerability research is moving quickly; check the linked sources for the latest figures and advisories.

Never miss an update

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

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.