DEVCON 2026    |    2-5 November 2026 – QEII Centre – London, UK    |    Register now! 

Blogs

When a CVE Isn't a Liferay Vulnerability

Why a vulnerable dependency doesn’t always mean Liferay DXP is vulnerable

David H Nebinger
David H Nebinger
9 من الدقائق قراءة

Security scanners are very good at finding things.

Run one against a Liferay DXP installation and it will inventory third-party libraries, determine their versions, compare those versions against vulnerability databases such as the NVD, and produce a list of CVEs.

Then somebody opens a Liferay Support ticket.

We're running version X of library Y. CVE-Z says that version is vulnerable. When will Liferay upgrade it?

Sometimes the answer is exactly what you would expect: Liferay upgrades the library.

But quite often the answer is something closer to:

Liferay DXP is not affected by this vulnerability.

That answer can be frustrating, particularly when the scanner has assigned the finding a High or Critical severity. The JAR is there. The version matches. The CVE exists. How can Liferay say it isn't vulnerable?

Because those are actually three different statements.

The library is present.

A vulnerability exists in that version of the library.

That vulnerability can be exploited through Liferay DXP.

A security scanner can usually establish the first two. Establishing the third requires understanding how the software actually works.

And that is where things get interesting.

The Scanner Isn't Wrong

Let's start by giving the scanner some credit.

If the scanner says that Liferay contains a particular version of a third-party library and that version is associated with a CVE, it may be completely correct.

The mistake is treating that information as proof that the resulting Liferay installation is exploitable.

Software Composition Analysis tools generally work from something resembling this model:

That's useful information, but it is only the beginning of vulnerability analysis.

A CVE usually applies to some particular behavior within a library. Exploiting it may require a certain class to be used, a particular feature to be enabled, a specific configuration, attacker-controlled input to reach a particular method, or some combination of all of these.

If the application never exposes that attack surface, the vulnerable code can physically exist inside the JAR without providing an exploitable path through the application.

The scanner has identified a potential vulnerability.

Now someone has to determine whether it is a reachable vulnerability.

Spring Is a Good Example

Consider Spring 6.2.9 as an example.

There are several CVEs associated with Spring components around these versions, including:

CVE Area Important Exploitation Condition
CVE-2025-41242 Spring MVC path traversal Requires particular Spring static-resource handling combined with a Servlet container that does not reject the malicious path sequences.
CVE-2025-22228 Spring Security BCryptPasswordEncoder Requires use of the affected password encoder behavior with passwords longer than 72 characters.
CVE-2025-41249 Spring annotation detection Relevant when Spring Security method security is enabled and authorization annotations occur in particular parameterized type hierarchies.

These aren't hypothetical qualifications added by Liferay. They come directly from Spring's own security advisories. For example, Spring says CVE-2025-41242 depends on several conditions and specifically notes that default Tomcat and Jetty security behavior prevents the vulnerability. CVE-2025-41249 similarly identifies @EnableMethodSecurity as part of the affected scenario.

CVE-2025-22228 affects BCryptPasswordEncoder.matches() when passwords exceed 72 characters and the first 72 characters match. Again, that is a real vulnerability, but an application has to actually use that Spring Security functionality in an exploitable authentication path before it becomes an application vulnerability.

And who knows? By the time you're reading this there may be several more CVEs associated with these versions.

That's the nature of modern software.

What matters is what happens next.

Presence Is Not the Same as Exploitability

When Liferay's application security team evaluates one of these reports, the CVE number and library version are just the starting point.

The real questions look more like this:

  1. What exactly is the vulnerable code?
  2. What conditions are required to exploit it?
  3. Does Liferay use that code?
  4. Is the vulnerable capability enabled?
  5. Can an attacker reach it?
  6. Can attacker-controlled input reach the vulnerable path?
  7. Does Liferay's own configuration or surrounding architecture prevent the exploit?

Only after answering those questions can you determine the actual risk to Liferay DXP.

This concept is often called reachability.

Imagine a third-party JAR containing 5,000 classes. One method in one class contains a vulnerability.

If Liferay never loads that class, never invokes that method, never enables the associated feature, and provides no path for attacker-controlled input to reach it, replacing the entire JAR may change the version number reported by your scanner without materially improving the security of the platform.

That's an important distinction.

Security isn't about achieving the highest possible dependency version number.

It's about eliminating exploitable attack paths.

What Happens When Liferay Investigates a CVE?

Liferay has a dedicated application security team continuously reviewing vulnerabilities reported against both Liferay code and the third-party software included with DXP.

Often the CVE has already been investigated before a customer reports it through Support.

The analysis goes deeper than the CVE headline.

The team looks at what causes the vulnerability, what is required to exploit it, and how a working exploit would behave. Then they compare those requirements against the way the affected library is actually being used by Liferay DXP.

The team also leverages tools like Konvu and other AI tools during the analysis to ensure it's not a cursory review.

You can read more about CVEs the security team has reviewed along with their classifications here: https://support.liferay.com/security-vulnerabilities.

Sometimes that analysis concludes that Liferay is affected.

Sometimes it concludes that Liferay is not affected.

There are even cases where the answer depends on configuration.

That's exactly the kind of application-level context that a simple dependency/version scan cannot provide.

The Log4j 1 Lesson

Anyone who dealt with enterprise security scanning during the later years of Log4j 1 probably remembers this problem particularly well.

Log4j 1 reached end of life, but applications continued using it for years afterward. As vulnerabilities were discovered, scanners accumulated an increasingly alarming collection of findings.

Some of them were severe.

CVE Component Attack Surface
CVE-2019-17571 SocketServer Deserialization through the Log4j network logging server.
CVE-2021-4104 JMSAppender JNDI behavior associated with JMS logging configuration.
CVE-2022-23302 JMSSink JNDI and deserialization behavior through the JMS sink.
CVE-2022-23305 JDBCAppender SQL injection through the database logging appender.
CVE-2022-23307 Chainsaw Deserialization in the Chainsaw logging viewer.

These vulnerabilities were real. Nobody was disputing that.

But look at the affected functionality.

Liferay wasn't running a Log4j SocketServer.

It wasn't using Chainsaw.

It wasn't using the JDBCAppender.

It wasn't using the vulnerable JMS logging components.

There was no route through a normal Liferay DXP installation for an attacker to reach those vulnerable features.

That didn't stop scanners from finding them.

From the scanner's perspective, everything was working exactly as designed:

The scanner had no idea whether Liferay was using JDBCAppender, SocketServer, or anything else inside the library.

It only knew the library was there.

But Sometimes "Not Vulnerable" Isn't Enough

This creates a practical problem.

A Critical CVE sitting on a security report is difficult for many organizations to accept, even when the vendor has analyzed it and determined that the product is not affected.

Security policy might say every Critical CVE must be eliminated.

An auditor might require remediation.

A customer's vulnerability management platform may refuse to close the finding.

And eventually someone asks:

Why doesn't Liferay just upgrade the library and make the scanner happy?

The Log4j 1 situation became a good example of how this can play out.

Apache had stopped maintaining Log4j 1, while moving directly to Log4j 2 represented a much larger technical change.

An intermediate solution was reload4j.

Reload4j is a binary-compatible fork of Log4j 1.2.17 designed specifically to harden the old Log4j implementation against these kinds of vulnerabilities. Among other changes, it addressed the JMSAppender, JMSSink, SocketServer, Chainsaw, and JDBCAppender issues.

Liferay adopted reload4j for earlier DXP releases while eventually moving DXP 7.4 to Log4j 2.

That gave Liferay a migration path without forcing a risky architectural change into older supported releases merely to satisfy dependency scanners.

The Three Basic Outcomes

When a vulnerability is identified in a third-party dependency, there are generally three reasonable outcomes.

The Product Isn't Affected

The investigation can establish that the vulnerable capability isn't reachable through Liferay.

No code change may be necessary.

I tend to prefer not affected or not exploitable in Liferay's usage over the phrase false positive here.

The CVE itself isn't false.

The scanner may have correctly identified the library.

What is false is the conclusion that the CVE necessarily represents an exploitable Liferay vulnerability.

This decision should never be made casually. It requires understanding both the vulnerability and Liferay's use of the affected library.

Patch or Harden the Dependency

Sometimes the vulnerability matters, but upgrading isn't practical.

The upstream project may be abandoned. The fixed version may contain incompatible changes. The affected capability may be something Liferay doesn't need at all.

In those cases, a focused patch or hardened dependency can make more sense than a major upgrade.

Removing unused vulnerable functionality can be particularly effective because code that no longer exists has a remarkably small attack surface.

Of course, maintaining patches to somebody else's software has a cost too. Whenever possible, fixes should remain aligned with or be contributed back to the upstream project rather than creating a permanent private fork.

Upgrade the Dependency

And sometimes upgrading really is the correct answer.

If a compatible maintenance release contains the fix, upgrading can be relatively straightforward.

The difficulty increases significantly when remediation requires a major version change.

At that point this isn't a security patch anymore.

It is a software upgrade.

Why Not Just Upgrade Every Time?

If you've ever upgraded Liferay itself, you already know the answer.

Software libraries are dependencies because applications depend on them.

Changing a major dependency can introduce:

  • API incompatibilities
  • behavioral changes
  • transitive dependency changes
  • classloading differences
  • OSGi package compatibility issues
  • configuration changes
  • unexpected runtime regressions

Even a library that compiles successfully after an upgrade can behave differently at runtime.

Then the updated platform has to be tested.

Liferay releases go through extensive testing precisely because changing something deep in the platform can have consequences far away from the code that changed.

This leads to a somewhat counterintuitive security principle:

An unnecessary security upgrade is not risk free.

Suppose Liferay establishes with high confidence that a particular CVE cannot be exploited through DXP.

Upgrading to a new major version of that dependency may therefore reduce essentially zero exploitable security risk while introducing new compatibility and regression risk.

That isn't automatically a good trade.

Security engineering should minimize total platform risk, not maximize dependency version numbers.

And engineering resources aren't infinite either.

Every week spent forcing unnecessary third-party upgrades through development, compatibility work, automated testing, manual testing, stabilization, and release engineering is time not being spent fixing actual vulnerabilities or improving the product.

I would much rather see those resources focused on exploitable security issues and meaningful improvements to Liferay DXP.

There Is One Important Catch: Your Code

There's another side to this discussion that customers building their own Liferay extensions need to understand.

When Liferay says a third-party CVE is not exploitable in Liferay DXP, that assessment applies to Liferay's use of the library.

Your customization can change that answer.

Suppose Liferay bundles a library containing a vulnerable feature but never uses that feature.

Then you create an OSGi module that imports the library and starts using exactly that functionality.

You may have just created the attack surface that didn't previously exist.

The same principle applies if you:

  • enable functionality that Liferay leaves disabled,
  • expose a library API through a custom REST endpoint,
  • pass attacker-controlled input into code that Liferay only uses with trusted data,
  • introduce a vulnerable appender, parser, serializer, or network listener,
  • or change security-related configuration around a bundled dependency.

At that point, the original Liferay analysis may still be completely correct.

Liferay isn't vulnerable. Your customization is.

This is one reason security analysis for customized Liferay installations can't stop with Liferay's own vulnerability statements.

Your code is part of the application too.

Don't Replace Liferay JARs Just to Silence a Scanner

This leads to one final warning.

When customers encounter one of these findings, there can be a temptation to "fix" the problem themselves by dropping a newer version of the affected JAR into Liferay.

Don't do that casually.

Liferay is a large application with carefully managed dependency versions, OSGi package relationships, transitive dependencies, and runtime expectations.

Replacing a platform dependency underneath it can create subtle failures that are extremely difficult to diagnose.

It can also move the installation outside the configuration Liferay Support has actually tested and supports.

You may successfully make the CVE disappear from the scan while introducing an entirely different production problem.

That's not security improvement.

That's vulnerability-report whack-a-mole.

What Should You Do With a Scanner Finding?

Security scans are still valuable.

When one identifies a third-party CVE in Liferay, report it. Include the library, version, CVE, scanner output, and any information you have about how you believe the vulnerability could be exploited.

But the most useful question isn't:

When will you upgrade this JAR?

A better set of questions is:

Is Liferay DXP affected by this CVE?

Is the vulnerable functionality used by Liferay?

Under what configuration would the vulnerability become exploitable?

Does the assessment apply only to Liferay out of the box, or are there concerns for custom OSGi modules?

Those questions get us much closer to the thing we actually care about.

Risk.

A CVE Is the Beginning of the Investigation

A CVE deserves attention.

A Critical CVE deserves serious attention.

But a CVE attached to a third-party JAR isn't automatically proof that the application containing that JAR is vulnerable.

Good vulnerability management requires more than matching version numbers.

It requires understanding attack surfaces, reachability, configuration, data flow, and how the affected software is actually being used.

Sometimes that investigation should result in an immediate dependency upgrade.

Sometimes it should result in a targeted patch.

And sometimes the technically correct answer really is:

Liferay DXP is not affected.

That doesn't mean the CVE was ignored.

Quite the opposite.

It means someone did the work that the scanner couldn't.

And that is exactly what we should want from a product security team.

The goal isn't to make every CVE identifier disappear from a dependency report at any cost. The goal is to keep exploitable vulnerabilities out of the platform while avoiding unnecessary changes that introduce new compatibility and operational risk.

So the next time a scanner finds a CVE in a third-party library bundled with Liferay, don't stop at:

Is this version listed in the NVD?

Ask the more important question:

Can an attacker actually reach and exploit it through our Liferay environment?

The scanner gives you the starting point.

It doesn't always give you the verdict.

تعليقات الصفحة

Related Assets...

لا توجد نتائج

More Blog Entries...

Ben Turner
سبتمبر ٠٢, ٢٠٢٦
David H Nebinger
أغسطس ١٨, ٢٠٢٦
David H Nebinger
أغسطس ١٦, ٢٠٢٦