Skip to content

PVADMIN-50363: Fix CVE-2026-6009 in net.sf.jasperreports:jasperreports#3

Open
RxL-Deepak-Agrawal wants to merge 3 commits into
release_6.4.0from
task/PVADMIN-50363
Open

PVADMIN-50363: Fix CVE-2026-6009 in net.sf.jasperreports:jasperreports#3
RxL-Deepak-Agrawal wants to merge 3 commits into
release_6.4.0from
task/PVADMIN-50363

Conversation

@RxL-Deepak-Agrawal

Copy link
Copy Markdown
Collaborator

Summary

Back-ports the upstream fix for CVE-2026-6009 (CWE-502, deserialization → RCE, CVSS 8.7) onto the 6.4.0 fork line. JRValueStringUtils deserialized BASE64-encoded report value
strings of non-built-in types through a plain, unfiltered ObjectInputStream, allowing arbitrary gadget-chain deserialization via a crafted .jasper value or subreport value. Value
deserialization is now routed through a filtered stream guarded by a ValueClassFilter.

Manual port — cherry-pick was infeasible (layout drift core/src/main/java vs jasperreports/src, and the fork inlines filtering in ContextClassLoaderObjectInputStream instead of
extending FilteredObjectInputStream).

⚠️ Security-sensitive: this change touches untrusted-data deserialization. Recommend human security review.

CVE details

CVE CVE-2026-6009
Type Deserialization of Untrusted Data (CWE-502)
Severity High — CVSS 8.7 (v4.0)
Package net.sf.jasperreports:jasperreports
Affected all versions < 7.0.7 (fork base 6.4.0.x-Rx in range)
Fixed upstream 7.0.7
Upstream commit 10f3862 ("filter classes on value deserialization", JSSEC-163)
Issue / PR upstream Jaspersoft#587 / Jaspersoft#588

Changes

  • AbstractClassFilter now implements DeserializationFilter (1-line change).
  • NEW FilteredObjectInputStream — pluggable DeserializationFilter; resolveClass filtering identical to upstream; reuses the fork's existing CountInputStream so the
    deserialization.byte.count.limit defense applies to the value path too.
  • NEW ValueClassFilter (extends AbstractClassFilter) — separate value.deserialization.class.whitelist.* namespace; @Property annotations dropped (annotation infra absent on
    6.4.0).
  • JRValueStringUtils routes value deserialization through FilteredObjectInputStream + ValueClassFilter, gated by the existing deserialization.class.filter.enabled flag (default
    true).
  • New message key value.deserialization.class.not.visible.
  • Version bump 6.4.0.3-Rx6.4.0.4-Rx (separate commit).

Conflict resolution / adaptation notes

  • Layout/inlining divergence — ported manually rather than cherry-picked; ContextClassLoaderObjectInputStream left untouched (it has fork-specific context-classloader fallback + AWT
    font logic), so it is not re-parented to FilteredObjectInputStream.
  • @Property annotations dropped — no annotation infrastructure on the 6.4.0 line (same as the CVE-2025-10492 back-port).
  • config.reference.xml not ported — that file is a 7.x doc artifact absent on the fork; the runtime property works regardless.
  • Whitelist inheritance is upstream-faithfulValueClassFilter (via AbstractClassFilter) loads the shared DeserializationClassWhitelist extensions, so value deserialization is
    restricted to the curated report whitelist plus any value.deserialization.class.whitelist.* entries. Verified AbstractClassFilter is byte-identical to upstream in this respect.

Behavior change

With the filter enabled (default), custom Serializable value objects going through the BASE64 DefaultSerializer path are rejected unless on the curated whitelist or explicitly added
via value.deserialization.class.whitelist.<name>. Common typed values (String/Integer/Date/etc.) use their own serializers and are unaffected.

Out of scope (follow-up)

The fork's VirtualizationObjectInputStream is unfiltered — a pre-existing divergence from the CVE-2025-10492 back-port, not part of this CVE. Recommend a separate ticket.

Test plan

  • Module compiles (JDK 8, mvn compile)
  • New JRValueStringUtilsFilterTest (5 cases) passes — gadget executes when disabled, blocked when enabled (value.deserialization.class.not.visible), value-whitelist namespace
    honored, shared report whitelist inherited, end-to-end JRValueStringUtils round-trip blocks gadget under defaults
  • Existing ContextClassLoaderObjectInputStreamFilterTest (4 cases) still passes
  • Strict diff-vs-upstream: no dropped security logic; byte-count + array-class-unwrap defenses preserved

Ticket: PVADMIN-50363 · Epic: PVADMIN-50285

RxL-Deepak-Agrawal and others added 3 commits June 25, 2026 17:41
Manually port the upstream value-deserialization filter from
Jaspersoft/jasperreports 7.0.7 (commit 10f3862,
JSSEC-163) onto the 6.4.0 line. Cherry-pick was infeasible due to layout drift
(core/src/main/java vs jasperreports/src) and because the fork inlines filtering
in ContextClassLoaderObjectInputStream rather than extending FilteredObjectInputStream.

JRValueStringUtils.DefaultSerializer deserialized BASE64-encoded value strings
of non-built-in types through a plain ObjectInputStream, allowing arbitrary
gadget deserialization (RCE) via a crafted .jasper value or subreport value.
It now routes through a new FilteredObjectInputStream guarded by a ValueClassFilter.

Changes:
- NEW DeserializationFilter: ClassLoaderFilter + isFilteringEnabled() (identical to upstream).
- AbstractClassFilter now implements DeserializationFilter.
- NEW FilteredObjectInputStream: pluggable DeserializationFilter; resolveClass
  filtering identical to upstream; reuses the fork's existing CountInputStream so
  the deserialization.byte.count.limit defense applies to the value path too.
- NEW ValueClassFilter (extends AbstractClassFilter): separate
  value.deserialization.class.whitelist.* namespace; @Property annotations dropped
  (annotation infra does not exist on the 6.4.0 line).
- JRValueStringUtils routes value deserialization through FilteredObjectInputStream
  + ValueClassFilter, gated by the existing deserialization.class.filter.enabled flag.
- New message key value.deserialization.class.not.visible.

Value deserialization is now restricted to the curated deserialization whitelist
(shared via DeserializationClassWhitelist extensions, upstream-faithful) plus any
value.deserialization.class.whitelist.* entries; arbitrary classes are rejected.

Reproducer JRValueStringUtilsFilterTest proves the RCE path is closed: an arbitrary
Serializable gadget runs only when the filter is disabled, is rejected with the
value.deserialization.class.not.visible key when enabled, and the public
JRValueStringUtils round-trip blocks it under default (filter-enabled) settings.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant