Fix Shadow API Exposure in Spring WebFlux
Shadow APIs in Spring WebFlux are undocumented, unmonitored endpoints that bypass security controls. They usually manifest as functional RouterFunctions or legacy @RestControllers that aren't mapped in the SecurityWebFilterChain. If you aren't explicitly denying unknown paths, you're leaking attack surface. Secure WebFlux requires a 'Deny-by-Default' posture at the filter level.
The Vulnerable Pattern
@Configuration public class ShadowConfig { @Bean public RouterFunctionshadowRoutes() { return route(GET("/internal/debug/dump"), req -> ServerResponse.ok().bodyValue("Sensitive Thread Dump...")); } }
@EnableWebFluxSecurity public class SecurityConfig { @Bean public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) { return http.authorizeExchange(exchanges -> exchanges .pathMatchers(“/api/public/**“).permitAll() // Shadow API /internal/debug/dump is NOT matched here, // and without a final denyAll(), it might be exposed depending on global config. ).build(); } }
The Secure Implementation
To kill Shadow APIs, you must shift from an 'Allow-List' to a 'Strict-Deny' architecture. The vulnerable code fails because it doesn't account for routes defined outside the main security context. By adding '.anyExchange().denyAll()', you ensure that any 'shadow' route added by a developer—whether via RouterFunction or @RequestMapping—is unreachable unless a security rule is explicitly written for it. Furthermore, always prefix your API versions to make broad path-matching more effective and less prone to accidental exposure.
@EnableWebFluxSecurity public class HardenedSecurityConfig { @Bean public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) { return http .authorizeExchange(exchanges -> exchanges .pathMatchers("/api/v1/public/**").permitAll() .pathMatchers("/api/v1/private/**").authenticated() // The Kill Switch: Any route not explicitly defined above is dropped. .anyExchange().denyAll() ) .csrf(csrf -> csrf.disable()) .build(); }@Bean public RouterFunction<ServerResponse> documentedRoutes() { return route(GET("/api/v1/private/stats"), req -> ServerResponse.ok().bodyValue("Secure Data")); }
}
Your Spring WebFlux API
might be exposed to Shadow API Exposure
74% of Spring WebFlux apps fail this check. Hackers use automated scanners to find this specific flaw. Check your codebase before they do.
Free Tier • No Credit Card • Instant Report
Verified by Ghost Labs Security Team
This content is continuously validated by our automated security engine and reviewed by our research team. Ghost Labs analyzes over 500+ vulnerability patterns across 40+ frameworks to provide up-to-date remediation strategies.