How Spring Boot EndpointRequest.to() Security Bypass Happens in Java Spring Boot and How to Fix It
Introduction
In the anti-corruption-layer service's pom.xml, Orbis AppSec's scanner flagged a high-severity vulnerability (CVE-2025-22235) in org.springframework.boot:spring-boot version 3.4.4. The issue lies deep within Spring Boot's security infrastructure: when you use EndpointRequest.to() to create a security matcher for an actuator endpoint that isn't currently exposed, the resulting matcher is incorrect — potentially matching the wrong URLs or creating an overly permissive security rule.
This matters because many Spring Boot applications use EndpointRequest.to() in their SecurityFilterChain configuration to apply specific access rules to actuator endpoints like /actuator/health, /actuator/env, or /actuator/shutdown. When the matcher misbehaves, your carefully crafted security rules may not protect what you think they're protecting.
The vulnerable dependency was declared in the project's root pom.xml:
<spring-boot.version>3.4.4</spring-boot.version>
The Vulnerability Explained
Spring Boot Actuator provides operational endpoints for monitoring and managing your application. Developers commonly write security configurations like:
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(auth -> auth
.requestMatchers(EndpointRequest.to("shutdown")).hasRole("ADMIN")
.requestMatchers(EndpointRequest.to("health", "info")).permitAll()
.anyRequest().authenticated()
);
return http.build();
}
The critical flaw in Spring Boot 3.4.4 (and earlier affected versions) is that when EndpointRequest.to("shutdown") is called but the shutdown endpoint is not exposed (which is the default — most dangerous endpoints are disabled by default), the resulting RequestMatcher doesn't correctly resolve to "match nothing." Instead, it can create a matcher that behaves unexpectedly.
The Attack Scenario
Consider this real-world scenario with the anti-corruption-layer service:
- A developer configures security rules using
EndpointRequest.to()for an endpoint that isn't exposed (e.g.,shutdown,env, orbeans). - The incorrect matcher could potentially match other request paths that weren't intended to be covered by that rule.
- If the rule was
permitAll()(common for health checks), an attacker could access paths that should require authentication. - If the rule was restrictive (e.g.,
denyAll()), the wrong matcher could inadvertently block legitimate requests, causing a denial-of-service condition.
Because this is a Java service handling HTTP requests, the vulnerability is remotely exploitable — any client that can reach the service can potentially exploit the misconfigured matchers.
Why This Is Particularly Dangerous
The insidious nature of this vulnerability is that:
- It only manifests when endpoints are not exposed — the exact scenario where developers assume they're safe
- Security configurations appear correct in code review
- Standard integration tests may pass because they often test exposed endpoints
- The mismatch between intended and actual security behavior is silent
The Fix
The fix is straightforward but critical: upgrade org.springframework.boot:spring-boot from version 3.4.4 to 3.4.5.
Before (vulnerable):
<spring-boot.version>3.4.4</spring-boot.version>
After (fixed):
<spring-boot.version>3.4.5</spring-boot.version>
This single-line change in the root pom.xml at line 42 updates the Spring Boot version property that governs all Spring Boot dependencies across the project, including the anti-corruption-layer module where the vulnerability was detected.
In Spring Boot 3.4.5, the EndpointRequest.to() method correctly handles the case where the specified actuator endpoint is not exposed. When an endpoint isn't available, the matcher now properly resolves to a "match nothing" state, ensuring that:
- Security rules for unexposed endpoints don't accidentally apply to other paths
- The security configuration behaves exactly as the developer intended
- No unintended access is granted through matcher confusion
For projects still on the 3.3.x branch, the equivalent fix is upgrading to 3.3.11.
Prevention & Best Practices
-
Keep dependencies current: Use automated dependency management tools to stay on top of security patches. Spring Boot releases security fixes regularly.
-
Test security configurations with unexposed endpoints: Write integration tests that verify your
SecurityFilterChainbehaves correctly even when actuator endpoints are disabled:
@Test
void whenEndpointNotExposed_securityRulesStillApplyCorrectly() {
// Test that non-exposed endpoint matchers don't affect other paths
webTestClient.get().uri("/api/sensitive-data")
.exchange()
.expectStatus().isUnauthorized();
}
- Explicitly configure endpoint exposure: Don't rely on defaults alone. Be explicit in
application.yml:
management:
endpoints:
web:
exposure:
include: health, info
exclude: env, beans, shutdown
-
Use Software Composition Analysis (SCA): Tools like Trivy, Snyk, or OWASP Dependency-Check can flag known CVEs in your dependency tree before they reach production.
-
Apply the principle of least privilege: Only expose actuator endpoints that are strictly necessary, and always require authentication for sensitive ones.
Key Takeaways
EndpointRequest.to()with unexposed endpoints is silently broken in Spring Boot ≤3.4.4 — your security rules may not be doing what you think they're doing.- The anti-corruption-layer's
pom.xmlcontrolled the Spring Boot version for the entire project — a single version property change fixes the vulnerability across all modules. - Default actuator endpoint exposure settings (most endpoints disabled) actually triggered this bug — the "secure by default" configuration paradoxically created the conditions for the vulnerability.
- Dependency version bumps from 3.4.4 → 3.4.5 are not just feature updates — they contain critical security fixes that address matcher logic in Spring Security integration.
- Static security rules in code can become dynamically incorrect when the underlying framework has bugs in matcher resolution — always verify with runtime tests.
How Orbis AppSec Detected This
- Source: The
pom.xmldependency declaration fororg.springframework.boot:spring-bootversion 3.4.4 in the anti-corruption-layer module - Sink:
EndpointRequest.to()matcher creation in Spring Boot's security filter chain, which produces incorrect URL matching logic when actuator endpoints are not exposed - Missing control: The vulnerable Spring Boot version lacked proper handling for the "endpoint not exposed" case in
EndpointRequest.to(), failing to return a correct "match nothing" matcher - CWE: CWE-284 (Improper Access Control)
- Fix: Upgraded
spring-boot.versionfrom 3.4.4 to 3.4.5 in the rootpom.xml, which includes the corrected matcher logic
Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.
Conclusion
CVE-2025-22235 is a subtle but high-impact vulnerability that undermines the security guarantees developers expect from Spring Boot's actuator endpoint matchers. The fact that it only manifests when endpoints are not exposed makes it particularly treacherous — the very configuration that seems most secure is the one that triggers the bug. By upgrading to Spring Boot 3.4.5 (or 3.3.11), you ensure that EndpointRequest.to() correctly handles all endpoint states, and your security configuration works exactly as intended. Always keep your framework dependencies updated, and use automated scanning to catch these issues before they reach production.