Skip to content

Outdated and vulnerable components

CWE-1104CWE-1035CWE-937OWASP A06:2021Updated September 4, 20265 min read

Frameworks, libraries and servers with available security updates that have not been applied carry publicly documented vulnerabilities. For many of them, ready-made attack code exists. The attacker has to discover nothing: they read off the version and look up what is known.

Most vulnerabilities in an application have to be found. Not these: they sit in a public database, with a description, a severity score and often working attack code alongside. All an attacker has to do is establish which version you run. It is an easy state to drift into, and the upkeep can be kept manageable.

What are outdated components?

A modern application consists largely of code you did not write yourself: the framework, the web server, the database, the programming language, dozens to hundreds of libraries, and the container layers all of that runs in. Outdated and vulnerable components are the parts of that for which security updates exist that you have not applied.

What sets this category apart is its openness. When a vulnerability is found in a widely used component, it is responsibly disclosed, given a CVE number and publicly described after the update is released. That openness is necessary, since administrators have to know what to patch, but it works both ways. From that moment on, every attacker also knows exactly what is wrong and how to abuse it.

Compare it with a recall for a lock that has become known to open with one specific movement. The manufacturer supplies a replacement. Anyone who does not fit it has not merely a weak lock, but a lock whose weakness is described in a public manual.

How does an attacker exploit outdated components?

The attack begins with reconnaissance, and your application often helps with that itself.

Vulnerable:

HTTP/1.1 200 OK
Server: Apache/2.4.29 (Ubuntu)
X-Powered-By: PHP/7.2.24
X-Generator: Drupal 7.58
<script src="/js/jquery-1.8.3.min.js"></script>

Four lines give a complete inventory. An attacker looks these versions up in a public vulnerability database, finds which problems are known and whether attack code is available for them. The research required amounts to reading a page.

This is not only about servers. Your dependencies carry risks too, often without your having chosen them consciously:

$ npm audit
found 34 vulnerabilities (12 moderate, 18 high, 4 critical)
  critical  Prototype Pollution in lodash <4.17.21
  high      Regular Expression Denial of Service in semver <7.5.2

Of those thirty-four advisories, only a handful are genuinely relevant in practice, because the rest sit in code your application never calls. That nuance is exactly what is needed to stop the overview being ignored.

Safe:

The fix is not a one-off cleanup but a process that keeps running:

# In the pipeline: the build fails on a serious, reachable problem
- name: Check for vulnerable dependencies
  run: npm audit --audit-level=high

- name: Record the inventory
  run: npm sbom --sbom-format cyclonedx > sbom.json
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8

The headers now give away no version information. That does not fix the vulnerability, since the outdated component stays outdated, but it does force an attacker to search rather than read, and it makes automated scanning for vulnerable versions considerably less effective.

Hiding version numbers is a supplement, not a measure. An attacker can often still infer the version from behaviour, from the presence of specific files or from the exact wording of error messages. Never regard hiding as an alternative to updating.

What is the impact of outdated components?

The severity runs from medium to critical and is determined entirely by the vulnerability in question. That is also what makes this category difficult: it is not a flaw with a fixed weight but a category that can contain anything, from a small information leak to remote code execution without authentication.

The critical cases have become known under their own names. Log4Shell in a logging library and the vulnerability in a popular content management system led within days to mass, automated exploitation. Anyone running a vulnerable version at that moment was not specifically singled out but simply found by a scanner sweeping the whole internet.

That automated nature is the defining feature. With most vulnerabilities an attacker has to be interested in your organisation specifically. Not here: vulnerable versions are scanned for at scale, and everything that responds is attacked. Your size or visibility is irrelevant. What counts is how much time sits between the release of the update and the moment you apply it.

How do you detect outdated components?

From the outside it starts with reading what the application gives away itself: version information in HTTP headers, in HTML comments, in the filenames of JavaScript libraries, in the default files of the platform used and in error messages. A tester compares the versions found with public databases and assesses whether the known vulnerabilities are actually reachable in this setup.

On the inside it is about the dependency inventory. That explicitly includes what you pull in indirectly: a library you deliberately chose often brings dozens along that nobody has assessed. Testers check whether a current overview exists, whether a process reacts to new advisories, and how long it takes in practice for an update to be applied. AssistSec assesses not only which advisories are open, but whether the vulnerable path in your application can actually be reached, and that distinction determines whether something is urgent or can be planned.

How do you prevent outdated components?

  • Keep a current inventory of all components and versions, including indirect dependencies.
  • Check automatically for known vulnerabilities in your pipeline and fail the build on serious cases.
  • Assess per advisory whether the vulnerable path is reachable in your application, and set priorities on that basis.
  • Run only versions that still receive security updates; plan replacement before support ends.
  • Update frontend libraries too; they run on your domain and with your session.
  • Remove components and functionality you do not use, because unused code still has to be maintained.
  • Hide version information in headers and error messages as an additional layer.
  • Record how quickly you act after an update is released, and measure whether you meet that norm.
  • Follow advisories for the components you use actively rather than waiting.

Sources

Frequently asked questions

Must I always run the newest version?

Not necessarily the newest, but one that still receives security updates. A long-term supported release under active maintenance is fine. What you must avoid is a version for which no updates appear any more, because then every new vulnerability stays open.

Is a vulnerability in a library always exploitable?

No, and that matters when setting priorities. A vulnerability in a function your application never calls is theoretical. So analyse not only which versions you run, but whether the vulnerable path is actually reachable. That prevents you drowning in advisories.

Why are frontend libraries often forgotten?

Because they run on the user's machine rather than your server, which puts them outside the usual server maintenance. Yet they run on your domain and with your session. An outdated jQuery with a known problem is a real risk to your visitors.

How do I deal with a vulnerability without a fix?

First assess whether the vulnerable path is reachable in your situation. If it is, restrict access to that functionality, put a filter in front of it, or disable the component temporarily. Document that choice and plan the replacement; a temporary measure left in place becomes a structural risk.

Related articles

Press / to search · Esc