Spring Boot's auto-configuration philosophy means a lot of security-relevant behavior is decided by which starter dependencies are on the classpath and how a handful of properties files are set, rather than by explicit code most developers write and review. This guide covers the checklist that matters most in practice, starting with the single most Spring-specific exposure.
1. Secure Actuator Endpoints
Actuator endpoints expose operational data - health, metrics, environment variables, and (most dangerously) full JVM heap dumps - and several of the most sensitive ones are reachable by default unless explicitly restricted.
# application.yml - expose only what you actually need externally
management:
endpoints:
web:
exposure:
include: health,info
endpoint:
health:
show-details: never
If you need broader Actuator access for internal monitoring, restrict it by network (bind it to a different port only reachable internally) or require authentication via Spring Security, rather than leaving it open on the same public port as the application.
2. Spring Security Filter Chain Order
Security rules are evaluated in the order they're registered, and a broad rule registered before a specific one makes the specific one unreachable - the same class of mistake covered for Symfony's access_control in our Symfony security guide.
http.authorizeHttpRequests(auth -> auth
.requestMatchers("/admin/**").hasRole("ADMIN") // specific rule first
.requestMatchers("/**").permitAll() // broad rule last
);
3. Disable the H2 Console in Production
# application-prod.yml
spring:
h2:
console:
enabled: false
The H2 web console allows arbitrary SQL execution through a browser interface - convenient for local development against an in-memory database, and a direct path to full database access if it's ever reachable in a deployed environment.
4. CSRF Protection
Spring Security enables CSRF protection by default for stateful (session-based) applications. It's commonly disabled entirely to "make an API work" during development and never re-evaluated - if your application serves both a stateful web UI and a stateless token-authenticated API, scope the exemption to the API paths specifically rather than disabling it globally.
http.csrf(csrf -> csrf.ignoringRequestMatchers("/api/**"));
// Rather than csrf.disable() for the whole application
5. SQL Injection via JPQL and Native Queries
// Vulnerable: string-concatenated JPQL
String jpql = "SELECT o FROM Order o WHERE o.status = '" + status + "'";
// Fixed: named parameters, even in @Query annotations
@Query("SELECT o FROM Order o WHERE o.status = :status")
List findByStatus(@Param("status") String status);
6. Secrets Management
Database credentials and API keys in application.yml committed to version control is the Spring equivalent of a committed .env file. Use environment variable placeholders (${DB_PASSWORD}) and inject real values at deploy time, or use Spring Cloud Config/HashiCorp Vault for centralized secret management.
7. CORS Configuration
The same wildcard-origin-plus-credentials combination that causes real damage in every other framework applies here identically - see the CORS section of our Laravel security guide for the underlying mechanics, which are framework-independent.
8. Dependency Scanning
Spring's ecosystem has had its own share of high-severity CVEs (Spring4Shell being the most notable) - ./gradlew dependencyCheckAnalyze or the OWASP Dependency-Check Maven plugin in CI catches known-vulnerable versions before they reach production.
9. Rate Limiting
Spring Boot has no built-in rate limiter - bucket4j is the most common addition for per-endpoint or per-user request limits, particularly on authentication endpoints.
10. Security Headers
Spring Security sets several security headers by default (X-Content-Type-Options, X-Frame-Options), but Content-Security-Policy requires explicit configuration - it has no safe generic default, since it depends entirely on what your application actually loads.
Verifying From the Outside
Actuator exposure, missing headers, and CORS misconfiguration are all visible in the live application's responses, regardless of what the source code intends. Try Shieldome's Spring Boot security scanner - create a free account to run your first scan.