Application Security

Spring Boot Security and Dependency Management

Securing Spring Boot applications with dependency management BOMs, vulnerability scanning, and hardened configurations.

Shadab Khan
Application Security Architect
4 min read

Spring Boot is the dominant framework for Java microservices, and it pulls in a massive dependency tree. A minimal Spring Boot web application starts with over 50 transitive dependencies. When you add Spring Security, Spring Data, and a few starters, you are easily past 200. Managing the security of that tree requires deliberate effort.

Spring Boot's Dependency Management

Spring Boot uses a Bill of Materials (BOM) to manage dependency versions. When you declare spring-boot-starter-parent as your parent POM, or import spring-boot-dependencies in dependency management, Spring Boot pins compatible versions for hundreds of libraries:

<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>3.2.0</version>
</parent>

This is a security advantage. The Spring team tests these versions together and patches them as a set. When a CVE hits a library in the BOM, the next Spring Boot release includes the fix.

The catch: Spring Boot releases happen on a schedule. If a critical CVE drops in a dependency between Spring Boot releases, you need to override the version yourself:

<properties>
  <snakeyaml.version>2.2</snakeyaml.version>
</properties>

Actuator Security

Spring Boot Actuator exposes operational endpoints. In older Spring Boot versions, these were often publicly accessible by default. In Spring Boot 3.x, most actuator endpoints are secured, but misconfigurations are still common.

# application.yml
management:
  endpoints:
    web:
      exposure:
        include: health, info, metrics
  endpoint:
    health:
      show-details: when-authorized
  server:
    port: 8081  # Separate port for actuator

Rules:

  1. Never expose all actuator endpoints (include: "*") in production.
  2. Run actuator on a separate port that is not internet-accessible.
  3. Protect actuator endpoints with Spring Security.
  4. Be especially careful with env, configprops, and heapdump endpoints. They can leak secrets.
@Configuration
public class ActuatorSecurityConfig {
    @Bean
    public SecurityFilterChain actuatorSecurityFilterChain(HttpSecurity http) throws Exception {
        http.securityMatcher(EndpointRequest.toAnyEndpoint())
            .authorizeHttpRequests(auth -> auth
                .requestMatchers(EndpointRequest.to("health", "info")).permitAll()
                .anyRequest().hasRole("ACTUATOR_ADMIN")
            );
        return http.build();
    }
}

Spring Security Configuration

Spring Security 6.x (Spring Boot 3.x) uses a builder-based configuration:

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .csrf(csrf -> csrf.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()))
            .headers(headers -> headers
                .contentSecurityPolicy(csp -> csp.policyDirectives("default-src 'self'"))
                .frameOptions(frame -> frame.deny())
                .httpStrictTransportSecurity(hsts -> hsts.maxAgeInSeconds(31536000))
            )
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/public/**").permitAll()
                .requestMatchers("/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
            )
            .sessionManagement(session -> session
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            );
        return http.build();
    }
}

Common Spring Security Mistakes

  1. Permit all by default. Always deny by default and explicitly allow specific paths.
  2. Disabling CSRF without understanding the implications. Only disable CSRF if you exclusively use token-based authentication.
  3. Using in-memory users in production. The UserDetailsService with hardcoded credentials should never reach production.
  4. Not configuring CORS properly. allowedOrigins("*") is almost never correct.

Vulnerability Scanning

OWASP Dependency-Check

<plugin>
  <groupId>org.owasp</groupId>
  <artifactId>dependency-check-maven</artifactId>
  <version>9.0.6</version>
  <configuration>
    <failBuildOnCVSS>7</failBuildOnCVSS>
    <suppressionFile>dependency-check-suppressions.xml</suppressionFile>
  </configuration>
</plugin>

Use suppression files to handle false positives, not to hide real vulnerabilities:

<!-- dependency-check-suppressions.xml -->
<suppressions>
  <suppress>
    <notes>False positive: this CVE applies to a different product</notes>
    <cve>CVE-2023-XXXXX</cve>
  </suppress>
</suppressions>

Spring Boot's Built-in Checks

Spring Boot 3.x added dependency vulnerability checks. Check the Spring Boot release notes for security-related dependency updates with every release.

Production Hardening

Disable DevTools

Spring Boot DevTools should never be in production:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-devtools</artifactId>
  <scope>runtime</scope>
  <optional>true</optional>
</dependency>

The optional flag prevents DevTools from being included in the packaged JAR. Double-check your fat JAR to confirm.

Error Handling

Do not expose stack traces in production:

server:
  error:
    include-stacktrace: never
    include-message: never

Logging

Sanitize sensitive data from logs. Spring Boot's logging can inadvertently log request parameters, headers, and payloads that contain credentials.

SBOM Generation

<plugin>
  <groupId>org.cyclonedx</groupId>
  <artifactId>cyclonedx-maven-plugin</artifactId>
  <version>2.7.10</version>
  <executions>
    <execution>
      <phase>package</phase>
      <goals><goal>makeAggregateBom</goal></goals>
    </execution>
  </executions>
</plugin>

How Safeguard.sh Helps

Safeguard.sh integrates with your Spring Boot CI pipelines to ingest CycloneDX SBOMs and provide continuous dependency monitoring. It tracks which Spring Boot version each of your services runs, flags services on unsupported versions, and correlates your dependency tree against vulnerability feeds. When the next critical CVE hits a Spring ecosystem library, Safeguard.sh identifies every affected service across your organization within minutes, not days.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.