← Back to Feed CACHED · 2026-09-14 07:58:18 · CACHE_KEY CVE-2023-21939
CVE-2023-21939 · Disclosed 2023-04-18

Vulnerability in the Oracle Java SE

ASSESSED — NOISGATE
Vendor
Reassessed
Verdict:
Do you agree?
01 · The Real Story

This is a fire-escape door alarm on a building that bricked up the fire escape three years ago

CVE-2023-21939 is a sandbox-bypass flaw in the Swing (JLabel HTML-rendering) component of Oracle Java SE 8u361, 11.0.18, 17.0.6, 20 and GraalVM Enterprise Edition 20.3.9, 21.3.5, 22.3.1. By crafting a JLabel with embedded HTML <object> tags referencing org.apache.batik.swing.JSVGCanvas, an attacker can load a remote malicious SVG that triggers code execution via event listeners. Oracle describes the attack surface as *'clients running sandboxed Java Web Start applications or sandboxed Java applets that load and run untrusted code.'* The CVSS vector scores it AV:N/AC:L/PR:N/UI:N — implying trivial remote exploitation.

Oracle's MEDIUM / 5.3 rating was arguably fair *in 2023 on paper*, but even then it overstated real-world risk. The primary attack vector — Java applets and Web Start — has been dead in browsers since 2015–2017 (NPAPI removal in Chrome 45, Firefox 52, Edge launch). The Applet API was deprecated in JDK 9 and marked for removal in JDK 17. The secondary deserialization-chain vector (Y4Sec-Team PoC) requires Apache Batik-Swing and Mozilla Rhino on the classpath *plus* a deserializing endpoint accepting untrusted JLabel objects — a vanishingly rare stack in production. The integrity-only impact (I:L, no C or A) further limits blast radius. In September 2026, with three-plus years of patching cycles behind us and no KEV listing, no known campaigns, and EPSS at ~2.5%, this is a backlog item, not a priority.

"Swing sandbox bypass in a world where no browser runs Java applets anymore."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Identify a target running vulnerable Java + Swing

Attacker must find an endpoint running Oracle Java SE ≤ 8u361, 11.0.18, 17.0.6, or 20 and that actually uses the Swing GUI toolkit. Server-side Java (Spring Boot, Quarkus, etc.) virtually never loads Swing. This limits targets to legacy thick-client desktop apps or very unusual server configurations.
Conditions required:
  • Target runs an affected Java version
  • Target application loads javax.swing classes
Where this breaks in practice:
  • Server-side Java deployments — the vast majority of enterprise Java — do not use Swing at all
  • Most enterprises have patched Java at least once since April 2023, removing the vulnerable versions
Detection/coverage: Qualys QID 378632, Nessus plugin 174803, Tenable plugin 216439 all detect vulnerable JDK versions.
STEP 02

Deliver untrusted code to the sandbox (Applet/Web Start path)

The Oracle-documented attack path requires the victim to load attacker-controlled code inside a sandboxed Java applet or Web Start application. The attacker hosts a malicious .jnlp or applet page and lures the victim to visit it. The Java sandbox is supposed to contain the code, but this CVE bypasses it to modify data.
Conditions required:
  • Victim's browser supports NPAPI or Java Web Start
  • Victim clicks a link and approves the Java security prompt
Where this breaks in practice:
  • No modern browser supports Java applets. Chrome removed NPAPI in 2015 (v45), Firefox in 2017 (v52). Edge never supported it.
  • Java Web Start was deprecated in JDK 9 (2017) and is unavailable in JDK 11+
  • Even on JDK 8 with Web Start, users must click through multiple security warnings
STEP 03

Deliver via deserialization chain (Y4Sec-Team PoC path)

The alternative attack path serializes a crafted JLabel object containing an HTML <object classid="org.apache.batik.swing.JSVGCanvas"> tag pointing to an attacker-controlled SVG. When the target application deserializes the object, Swing renders the HTML, Batik loads the SVG, and embedded JavaScript event listeners (via Rhino) execute arbitrary commands.
Conditions required:
  • Target application deserializes untrusted Java objects
  • Apache Batik-Swing (batik-swing) is on the classpath
  • Mozilla Rhino scripting engine is on the classpath
  • Outbound HTTP from the target to attacker infrastructure is allowed
Where this breaks in practice:
  • Deserializing untrusted Java objects is a well-known anti-pattern; modern frameworks use JSON/protobuf instead
  • Batik-Swing is uncommon in production server stacks; it's an SVG rendering library for GUI apps
  • The combination of Batik + Rhino + untrusted deserialization is extraordinarily rare
  • Egress filtering / proxy requirements block the outbound SVG fetch in hardened environments
Detection/coverage: Deserialization-focused WAFs (e.g., Contrast, jep290 filters) and RASP tools can detect or block gadget chains involving javax.swing.JLabel.
STEP 04

Achieve integrity impact

If the chain succeeds, the attacker gains the ability to perform unauthorized update, insert, or delete operations on data accessible to the Java process. Per Oracle's own advisory, there is no confidentiality impact and no availability impact — the scope is limited to partial integrity compromise. The Y4Sec PoC demonstrates command execution, but this requires the Batik+Rhino dependency chain which elevates beyond what the CVE itself provides.
Conditions required:
  • One of the two prior delivery paths succeeds
Where this breaks in practice:
  • Impact is scoped to I:L (low integrity) per Oracle's own CVSS vector
  • RCE via the PoC requires additional third-party libraries not guaranteed to be present
03 · Intelligence Metadata

The supporting signals.

In-the-wild exploitationNone known. Not listed on CISA KEV. No public reports of active campaigns exploiting this CVE as of September 2026.
Proof-of-conceptPublic. Y4Sec-Team/CVE-2023-21939 on GitHub. Extended PoC by win3zz on GitHub Gist demonstrating RCE via Batik+Rhino deserialization chain.
EPSS score0.02495 (~2.5%) — low probability of exploitation in the next 30 days. Well below the median for network-accessible vulns.
KEV statusNot listed. No CISA Known Exploited Vulnerability entry.
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N — Network-accessible, no privileges/interaction, but only low integrity impact. No confidentiality or availability damage.
Affected versionsOracle Java SE 8u361, 8u361-perf, 11.0.18, 17.0.6, 20; GraalVM Enterprise Edition 20.3.9, 21.3.5, 22.3.1.
Fixed versionsJava SE 8u371, 11.0.19, 17.0.7, 20.0.1; GraalVM EE 20.3.10, 21.3.6, 22.3.2. Distro backports: RHEL (RHSA-2023:1875), Debian (DSA-5388-1), Ubuntu (USN-6077-1), Amazon Linux (ALAS2-2023-2028).
Scanning / exposureShodan/Censys queries for exposed Java services are not directly applicable — the primary vector (applets) is client-side. Deserialization endpoints are not trivially fingerprinted externally.
Disclosure date2023-04-18, part of Oracle April 2023 Critical Patch Update.
Reporting researcherY4Sec Team (credited for public PoC research); original reporter to Oracle not publicly named.
04 · The Call

noisgate verdict.

Final Verdict
DOWNGRADED to LOW (2.5/10)

The single most decisive factor is the extinction of the primary attack surface: Java applets and Web Start have been unsupported in all major browsers since 2017, eliminating the documented remote attack vector for virtually 100% of enterprise endpoints. The secondary deserialization path requires an implausible three-library intersection (Swing + Batik + Rhino + untrusted deser) that excludes mainstream server-side Java deployments.

HIGH Attack-surface extinction (applet/Web Start path is dead)
HIGH No in-the-wild exploitation after 3+ years
MEDIUM Deserialization path rarity estimate (based on library co-occurrence, not telemetry)

Why this verdict

  • Dead attack vector: The Oracle advisory explicitly scopes this to 'clients running sandboxed Java Web Start applications or sandboxed Java applets.' Every major browser dropped Java plugin support by 2017. This path is non-functional on modern endpoints.
  • Implausible dependency chain for deserialization path: The PoC requires batik-swing + Rhino + an endpoint that deserializes untrusted JLabel objects. This triple intersection is extraordinarily rare in production. Most enterprise Java is server-side (Spring, Jakarta EE) and never loads Swing.
  • Integrity-only, low impact: The CVSS vector is C:N/I:L/A:N. Even if exploited, the attacker modifies *some* data — no secrets leaked, no DoS, no privilege escalation per the CVE scope.
  • Role multiplier: Java SE runs on CI/CD servers, app servers, and database tiers — all potentially high-value roles. However, Swing is a *desktop GUI toolkit*. High-value server roles (Jenkins, Tomcat, Spring Boot, Kafka) do not load Swing components or deserialize Swing objects. The blast radius on high-value roles is effectively nil because the vulnerable component (Swing JLabel HTML rendering) is not exercised in server deployments. No floor elevation applies.
  • Three years unpatched with no exploitation: Disclosed April 2023, no KEV, no campaigns, EPSS at 2.5%. The security community and threat actors have had ample time; the lack of uptake confirms the theoretical nature of this risk.

Why not higher?

The vulnerability has a public PoC and is theoretically network-accessible without authentication, which normally warrants at least MEDIUM. However, the primary attack vector is extinct (applets), the secondary vector requires a near-impossible library combination in production, and the impact is limited to low integrity with no confidentiality or availability loss. Elevating to MEDIUM would overstate actionable risk for any modern enterprise.

Why not lower?

A public PoC exists and the deserialization chain, while improbable, is technically functional. Rare legacy environments (e.g., manufacturing or government kiosks still running Java 8 with Web Start) could theoretically be affected. Dropping to IGNORE would be inappropriate given that the PoC achieves command execution under specific conditions.

05 · Compensating Control

What to do — in priority order.

  1. Confirm Swing is not loaded in production JVMs — Run jcmd <pid> VM.classloaders or check loaded classes for javax.swing on your server fleet. If Swing is not loaded — which is the expected case for server-side Java — this CVE has zero applicability. No SLA applies for LOW; treat as backlog hygiene.
  2. Audit deserialization endpoints — If any Java service accepts ObjectInputStream from untrusted sources, that is the real problem — not this specific CVE. Implement JEP 290 deserialization filters (jdk.serialFilter) globally. This addresses entire gadget-chain classes, not just CVE-2023-21939.
  3. Remove Batik and Rhino from classpaths where not needed — If batik-swing or rhino appear in your dependency tree but are unused, remove them. This eliminates the PoC chain entirely. Use mvn dependency:tree or gradle dependencies to audit.
  4. Block outbound HTTP from application servers — The PoC requires the victim JVM to fetch a remote SVG over HTTP. Egress filtering via proxy or firewall rules breaks this chain.
What doesn't work
  • Upgrading browsers — browsers already don't support Java applets; upgrading them doesn't change the risk posture for this CVE.
  • WAF rules for HTTP request patterns — the initial exploit delivery (deserialization) arrives via the application's own deserialization endpoint, not a standard HTTP exploit payload a WAF would pattern-match.
  • Java Security Manager hardening — the Security Manager itself was deprecated in JDK 17 and is being removed. It was also the mechanism this CVE bypasses, so tightening it is circular.
06 · Verification

Crowdsourced verification payload.

Run this on each target host where Java is installed. It checks the installed JDK/JRE version against the known-vulnerable ranges. No special privileges required beyond read access to the java binary. Example: bash check_cve_2023_21939.sh or bash check_cve_2023_21939.sh /usr/lib/jvm/java-11/bin/java

noisgate-verify.sh
BASHREAD-ONLYSAFE
#!/usr/bin/env bash
# CVE-2023-21939 version checker
# Checks if installed Java version is in the vulnerable range
# Exit codes: 0 = PATCHED, 1 = VULNERABLE, 2 = UNKNOWN

JAVA_BIN="${1:-java}"

if ! command -v "$JAVA_BIN" &>/dev/null; then
  echo "UNKNOWN - java binary not found at: $JAVA_BIN"
  exit 2
fi

VERSION_OUTPUT=$("$JAVA_BIN" -version 2>&1)
echo "Detected: $VERSION_OUTPUT" | head -1

# Extract version string
VER=$(echo "$VERSION_OUTPUT" | head -1 | sed -E 's/.*"([^"]+)".*/\1/')

# Parse major version
MAJOR=$(echo "$VER" | sed -E 's/^1\.([0-9]+)\..*/\1/' | sed -E 's/^([0-9]+)\..*/\1/')
if echo "$VER" | grep -qE '^1\.'; then
  MAJOR=$(echo "$VER" | cut -d. -f2)
else
  MAJOR=$(echo "$VER" | cut -d. -f1)
fi

# Parse update number for JDK 8
UPDATE=0
if [ "$MAJOR" = "8" ]; then
  UPDATE=$(echo "$VER" | sed -E 's/.*[_.]([0-9]+).*/\1/' || echo 0)
fi

# Parse minor for 11, 17, 20+
MINOR=$(echo "$VER" | cut -d. -f2)
PATCH=$(echo "$VER" | cut -d. -f3 | sed 's/[^0-9].*//')

case "$MAJOR" in
  8)
    if [ "$UPDATE" -le 361 ] 2>/dev/null; then
      echo "VULNERABLE - Java 8 update $UPDATE (fixed in 8u371+)"
      exit 1
    else
      echo "PATCHED - Java 8 update $UPDATE"
      exit 0
    fi
    ;;
  11)
    if [ "${MINOR:-0}" -eq 0 ] && [ "${PATCH:-0}" -le 18 ] 2>/dev/null; then
      echo "VULNERABLE - Java 11.0.${PATCH} (fixed in 11.0.19+)"
      exit 1
    else
      echo "PATCHED - Java $VER"
      exit 0
    fi
    ;;
  17)
    if [ "${MINOR:-0}" -eq 0 ] && [ "${PATCH:-0}" -le 6 ] 2>/dev/null; then
      echo "VULNERABLE - Java 17.0.${PATCH} (fixed in 17.0.7+)"
      exit 1
    else
      echo "PATCHED - Java $VER"
      exit 0
    fi
    ;;
  20)
    if [ "${MINOR:-0}" -eq 0 ] && [ "${PATCH:-0}" -eq 0 ] 2>/dev/null; then
      echo "VULNERABLE - Java 20.0.0 (fixed in 20.0.1+)"
      exit 1
    else
      echo "PATCHED - Java $VER"
      exit 0
    fi
    ;;
  *)
    if [ "$MAJOR" -gt 20 ] 2>/dev/null; then
      echo "PATCHED - Java $MAJOR is not affected"
      exit 0
    else
      echo "UNKNOWN - Unrecognized Java version: $VER"
      exit 2
    fi
    ;;
esac
07 · Bottom Line

If you remember one thing.

TL;DR
Don't reprioritize anything for this. CVE-2023-21939 targets a dead attack surface (Java applets/Web Start) and a near-impossible deserialization chain. If you're still running Java 8u361, 11.0.18, 17.0.6, or JDK 20.0.0 in September 2026, you have much bigger problems than this Swing flaw — those versions are years out of support. As a LOW under the noisgate remediation SLA, there is no mitigation SLA — treat this as backlog hygiene. Roll it into your next scheduled Java upgrade cycle. If you happen to have a legacy thick-client app still using Java Web Start on JDK 8, that environment deserves a broader modernization initiative, not a point patch for one CVE. Focus your team's time on vulns with actual exploitation.

Sources

  1. NVD - CVE-2023-21939
  2. Oracle April 2023 CPU Advisory
  3. Y4Sec-Team PoC Repository
  4. win3zz Extended PoC (GitHub Gist)
  5. Red Hat CVE Entry
  6. AWS ALAS CVE Detail
  7. Wiz Vulnerability Database
Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.