VNX-JAVA-027 – Java Spring Security Headers Disabled
Overview
Spring Security automatically adds a set of defensive HTTP response headers — X-Frame-Options, X-Content-Type-Options, X-XSS-Protection, Strict-Transport-Security, and Content-Security-Policy — when the headers() configuration is active (the default). Calling frameOptions().disable() disables the X-Frame-Options header specifically, while calling headers().disable() removes all security headers entirely. Both patterns leave the application exposed to clickjacking and related UI-redressing attacks. This is captured by CWE-693 (Protection Mechanism Failure).
This rule flags the two most common disablement patterns in Spring Security DSL code. Either pattern in a security configuration class indicates that a deliberate choice has been made to remove protective headers, which must be reviewed to confirm the decision is intentional and the risk is accepted.
The X-Frame-Options header is the primary defence against clickjacking: it prevents the application from being embedded in an <iframe> on a third-party page. Without it, an attacker can overlay an invisible iframe of the legitimate application over a deceptive page, tricking users into performing authenticated actions (transferring funds, changing account settings, approving access) without their knowledge.
Severity: Medium | CWE: CWE-693 – Protection Mechanism Failure
Why This Matters
Clickjacking attacks are difficult for users to detect because the malicious page looks entirely legitimate — the attacker’s visible UI element is placed precisely over a hidden, transparent iframe of the target application. The user interacts with what appears to be a harmless button or link but is actually submitting an authenticated request to the target application.
When headers().disable() is used, the application also loses Strict-Transport-Security (HSTS) and X-Content-Type-Options. Without HSTS, an active network attacker can downgrade HTTPS to HTTP on the user’s first visit. Without X-Content-Type-Options: nosniff, MIME-type sniffing attacks become possible in older browsers.
Spring Security’s default header configuration is safe and suitable for most applications. The headers().disable() call is most often introduced by developers following outdated tutorials or copying configurations from non-security-sensitive internal tools. The fix is always to restore the default or configure the headers explicitly rather than disable them.
What Gets Flagged
// FLAGGED: X-Frame-Options explicitly disabled
http
.headers()
.frameOptions().disable()
...
// FLAGGED: all HTTP security headers disabled
http
.headers().disable()
...
Remediation
Remove
frameOptions().disable()and replace it withframeOptions().deny()(prevents all framing) orframeOptions().sameOrigin()(allows framing only from the same origin).Remove
headers().disable()entirely. Spring Security’s default header set is appropriate for production use in virtually all applications.If embedding in a specific partner domain is required, configure a Content-Security-Policy
frame-ancestorsdirective rather than disablingX-Frame-Options.
// SAFE: explicit header configuration using Spring Security 6 lambda DSL
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.headers(headers -> headers
.frameOptions(frame -> frame.deny())
.contentSecurityPolicy(csp -> csp
.policyDirectives("default-src 'self'; frame-ancestors 'none'"))
.httpStrictTransportSecurity(hsts -> hsts
.includeSubDomains(true)
.maxAgeInSeconds(31536000))
)
// ... rest of configuration
;
return http.build();
}
// SAFE: allowing same-origin framing (e.g. for a dashboard with iframes)
http
.headers(headers -> headers
.frameOptions(frame -> frame.sameOrigin())
);