
Finding Gadgets Like It's 2026 (Atredis Partners)
Atredis Partners built an LLM-driven pipeline (WALA/ASM call-graph builder, a FastAPI graph query server, Claude Code as the reasoning/validation agent, and a dynamic test/debug runner) to automate discovery of Java deserialization gadget chains against modern, hardened application servers (WebSphere, WildFly, Payara). The project found 17 confirmed chains, 6 novel, including CB1-Shaded-RCE — a chain that bypasses JPMS's TemplatesImpl restrictions via a shaded/relocated copy of Xalan's XSLTC shipped inside WildFly's JSTL jar, giving RCE on the latest WildFly on JDK 21 — plus a novel JNDI-injection chain in Payara via AttributeComparator/InjectableJMSContext. The write-up details the architecture, methodology limitations (benchmark gaming, non-determinism), and broader implications for any app/server that bundles a shaded Xalan outside java.xml, with tooling released on GitHub (atredispartners/llmchainhunter).
What it is
Atredis's write-up establishes a concrete, checkable exposure surface: any application server or app that ships a shaded/relocated copy of Xalan's XSLTC outside the JDK's java.xml module re-enables TemplatesImpl bytecode-loading RCE that JPMS was supposed to kill in JDK 9+. The summary names CB1-Shaded-RCE on WildFly; what it can't carry are the specific namespaces to grep for, which servers ship the code but lack a trigger, and why WebSphere is immune.
How it works
JPMS blocks class Evil extends AbstractTranslet because AbstractTranslet lives in a non-exported JDK package. A shaded copy relocated into an application JAR is not JDK code, so JPMS does not apply — you extend the shaded AbstractTranslet, the shaded TransletClassLoader defines it, and Class.newInstance() runs your static initializer. On WildFly 39.0.1 the shaded copy lives in jakarta.servlet.jsp.jstl-3.0.1-jbossorg-1.jar, namespace org.eclipse.tags.shaded.org.apache.xalan, auto-loaded for every WAR. The trigger reaching it is PriorityQueue.readObject → BeanComparator.compare → TemplatesImpl.getOutputProperties, confirmed as RCE on JDK 21.0.10.
Preconditions / Affected
The RCE needs two things on the classpath: a shaded TemplatesImpl and a trigger gadget (Commons-BeanUtils, Commons-Collections 3/4, some Jackson versions, ROME, or Hibernate).
- WildFly 39.0.1 — exploitable. Ships both the shaded JSTL Xalan and Commons-BeanUtils.
- JBoss EAP (Jakarta EE 10+), GlassFish 7+, Payara 6+ — ship the shaded artifact but NO trigger. Exploitable only if a deployed app brings its own trigger. No bundled trigger was found in the short project.
- Jetty (
com.oracle.wls.shaded.org.apache.xalan) and TomEE (openejb.shade.org.apache.xalan) — shaded namespaces found; same "needs app-supplied trigger" caveat. - WebSphere (Liberty and traditional) — immune. Traditional runs IBM J9, whose
com.ibm.xtq.xslt.jaxp.TemplatesImplis not Serializable, has no_bytecodesfield, and loads translets by name. - The standalone
xalan:xalanMaven artifact (2.7.2 alone) has 112,000+ dependents; shaded copies also exist in Apache Drill, Oracle WebLogic, docx4j, and Karaf/ServiceMix/SpringSource OSGi bundles.
What to do
- Grep deployed classpaths for shaded Xalan namespaces outside
java.xml— known ones:org.eclipse.tags.shaded.org.apache.xalan,com.oracle.wls.shaded.org.apache.xalan,openejb.shade.org.apache.xalan. The authors note these are not on known deserialization blocklists. - Where a shaded
TemplatesImpland any trigger gadget coexist, treat it as live RCE regardless of JDK 9+/JPMS assumptions. - Verify RCE proof-of-approach as they did:
docker exec wildfly-deserialize-poc cat /tmp/rce-proof.txt- A second novel, non-RCE JNDI-injection chain in Payara (
PriorityQueue → AttributeComparator → InjectableJMSContext.toString → InitialContext().lookup) usesAttributeComparatoras atoStringtrigger — a replacement forBadAttributeValueExpException, which stopped working in JDK 18+. Worth noting if you rely on JDK 18+ as mitigation fortoString-triggered chains.
Caveats
Only 1 of the 17 confirmed chains (CB1-Shaded) reached RCE; most are variations on known chains. The pipeline is non-deterministic (different results per run) and the authors caught Claude Code "gaming" the ysoserial benchmark by recognizing known gadgets, which is why they pivoted to real targets. The WildFlyDataSource-JNDI chain the LLM flagged as novel was already documented by Synacktiv (2022). Tooling and runbook: github.com/atredispartners/llmchainhunter.
Organisations named here
- BeanComparator
- InvokerTransformer
- JNDI injection
- JPMS
- PriorityQueue-AttributeComparator-JNDI
- Synacktiv
- TemplatesImpl
- TransformingComparator
- WildFlyDataSource-JNDI
Technologies named here
- IBM WebSphere
- ysoserial
- GadgetInspector
- WildFly
- Payara
- Claude Code
- WALA
- JBoss EAP
- Java ASM library
- GlassFish
- SQLite
- Jetty
- TomEE
- Graph Query Server
- xalan:xalan
- CFR
- Apache Drill
- Dynamic Runner
- Oracle WebLogic
- RUNBOOK.md
- docx4j
- llmchainhunter
- Karaf
- ServiceMix
- SpringSource
- Commons-Collections
- Jackson
- ROME
- Hibernate
- Commons-BeanUtils
- Java
- WebSphere
Techniques named here
- Java deserialization gadget chain construction
- CB1-Shaded-RCE
- PriorityQueue-AttributeComparator-JNDI chain
- WildFlyDataSource-JNDI chain
- CC4-BeanComparator Bridge chains
- Type confusion for gadget discovery
- Class Hierarchy Analysis
- toString trigger for deserialization gadgets
Related in AppSec
Flowise MCP Security Bypass Enables RCE
Inside an Oracle Database SQL Injection Attack | Huntress
OASIS
