Fix cards for Java and Spring Boot
A01:2025 Broken Access Control
- Cross-site request forgery (CSRF)CWE-352
Keep Spring Security's CSRF protection on (it is the default) and never call csrf.disable() for browser-facing routes.
- Missing object-level authorization (IDOR and BOLA)CWE-862 · CWE-639 · CWE-863
Get the user from Spring Security with @AuthenticationPrincipal, never from request parameters, and scope every repository query with tenant_id = :tenant AND (owner_id = :user OR :isBillingAdmin).
- Open redirectCWE-601
Refuse backslashes and control characters, then parse next with java.net.URI: return "redirect:" + next only for a path that starts with exactly one slash, or an https URL whose host is in an exact allowlist with no port or user info; otherwise redirect to a fixed page.
- Path traversalCWE-22 · CWE-23 · CWE-36 · CWE-59
Compare real Path objects: base = baseDir.toRealPath(), target = base.resolve(name).toRealPath(), and serve only if target.startsWith(base). toRealPath() collapses ../ and follows symlinks, and Path.startsWith compares whole name elements, so /srv/files-secret fails.
- Server-side request forgery (SSRF)CWE-918
Attach the policy to the connection, not the hostname string.
A02:2025 Security Misconfiguration
- CORS misconfiguration on credentialed APIsCWE-942 · CWE-346
Declare a CorsConfigurationSource bean whose CorsConfiguration lists the front ends' exact origins from configuration with setAllowedOrigins and sets setAllowCredentials(true), and apply it with CorsFilter or http.cors().
- XML external entity (XXE) processingCWE-611 · CWE-776
Configure the XML parser to refuse the DTD: in Java set the Apache feature disallow-doctype-decl to true on the DocumentBuilderFactory, so any DOCTYPE is a fatal error and no external entity (CWE-611) or entity expansion (CWE-776) runs.
A04:2025 Cryptographic Failures
- Insecure randomness for security tokensCWE-330 · CWE-338
Generate the token with java.security.SecureRandom: 32 bytes (256 bits) Base64url-encoded.
- Weak password hashingCWE-916 · CWE-759 · CWE-327
Use Spring Security's DelegatingPasswordEncoder with an Argon2PasswordEncoder built from explicit parameters, new Argon2PasswordEncoder(16, 32, 1, 19456, 2), because defaultsForSpringSecurity_v5_8() is below OWASP's minimum.
A05:2025 Injection
- Code injectionCWE-94 · CWE-95
Do not evaluate request input as SpEL with a StandardEvaluationContext: it allows T(...) type references and method calls, so the formula runs code.
- Cross-site scripting (XSS)CWE-79
Bind text with th:text and attributes with th:attr or th:title, which HTML-escape & < > " and ' — never th:utext for user data.
- CSV formula injectionCWE-1236
Spreadsheets run a cell that starts with =, +, -, @, tab or carriage return.
- LDAP filter injectionCWE-90
Build the filter with Spring LDAP's LdapQueryBuilder (query().where("cn").is(name)), which puts every value through LdapEncoder.filterEncode (RFC 4515), so * ( ) \ and NUL are matched as data, not parsed as syntax.
- OS command and argument injectionCWE-78 · CWE-88
Build the process from a List so ProcessBuilder runs it directly - new ProcessBuilder(List.of(tool, "--", name)) - and no shell parses the arguments; the "--" makes a leading-dash operand data, not an option.
- Server-side template injectionCWE-1336 · CWE-94 · CWE-95
Evaluate user templates with a restricted context: SimpleEvaluationContext.forReadOnlyDataBinding() allows only property access on your data, so T(...) type references, constructors and reflection fail.
- SQL injectionCWE-89
Bind values with NamedParameterJdbcTemplate: write :name placeholders and pass a MapSqlParameterSource (or use JdbcTemplate with ? and arguments).
- XPath injectionCWE-643 · CWE-91
Parameterize the XPath. Compile the query with $username and $password variables and supply their values through an XPathVariableResolver, so a value such as ' or '1'='1 is compared as a literal and can never become query structure.
A06:2025 Insecure Design
- Regular-expression denial of service (ReDoS)CWE-1333
On JDK 9+ java.util.regex memoizes to defuse many catastrophic patterns - but a backreference turns that off, so a nested quantifier backtracks exponentially again, and the engine has no timeout.
- Unrestricted file uploadCWE-434 · CWE-646 · CWE-73 · CWE-770
Decide the type from the bytes, and never let the client pick the name.
A07:2025 Authentication Failures
- Hard-coded secretsCWE-798 · CWE-260
Bind the key from the Spring Environment with @ConfigurationProperties and check it in the record's constructor, so a missing or blank value stops the app at startup.
- Improper TLS certificate validationCWE-295 · CWE-297 · CWE-296
Never install a TrustManager or HostnameVerifier that accepts everything.
- JWT validation in APIs (bearer tokens)CWE-347 · CWE-287
Build the JwtDecoder bean with NimbusJwtDecoder.withPublicKey(key).signatureAlgorithm(RS256) (or withIssuerLocation for rotating keys) and set its validators: JwtValidators.createDefaultWithValidators(timestamps, new JwtIssuerValidator(issuer), new JwtAudienceValidator(audience)), with a JwtTimestampValidator that requires exp.
- Missing authentication for a critical functionCWE-306 · CWE-287
Verify a credential on the server before any critical route runs.
- Session fixation and session cookiesCWE-384 · CWE-613 · CWE-614 · CWE-1004 · CWE-1275
Let Spring Security sign users in (formLogin or another built-in mechanism) and keep sessionFixation at changeSessionId, the default; a custom login endpoint must invoke the SessionAuthenticationStrategy itself.
A08:2025 Software or Data Integrity Failures
- Insecure deserializationCWE-502
Do not deserialize untrusted bytes with ObjectInputStream: its readObject runs code chosen by the payload.
- Mass assignment (over-posting)CWE-915
Bind @RequestBody to a record that declares only the fields users may edit (here ProfileUpdate(displayName, bio)), never to the entity, and copy those fields onto the entity yourself.
A09:2025 Security Logging and Alerting Failures
- CRLF injection in logs and response headersCWE-117 · CWE-93 · CWE-113
Encode request values before they reach a log line, turning every control character into a visible escape, or use Spring Boot's structured JSON logging; never delete only LF.
Not covered in Java yet
These weaknesses have fix cards in other stacks but not in this one.
Supported versions
Each Spring Boot minor line gets about 13 months of open-source support; longer support is commercial. Spring Boot support policy.
| Version | Latest | Status | Released | End of support |
|---|---|---|---|---|
| 4.1.x | 4.1.1 | SupportedThe cards use it. | 10 June 2026 | 31 July 2027 |
| 4.0.x | 4.0.8 | SupportedOpen-source support ends on 2026-12-31; commercial support until 2027-12-31. | 20 November 2025 | 31 December 2026 |
| 3.5.x | 3.5.16 | End of lifeOpen-source support ended; commercial support until 2032-06-30. | 22 May 2025 | 30 June 2026 |
| Version | Latest | Status | Released | End of support |
|---|---|---|---|---|
| 25 (LTS) | 25.0.4.1 | Supported | 16 September 2025 | September 2031 |
| 21 (LTS) | 21.0.12.1 | SupportedThe cards run OpenJDK 21.0.12.1. | 19 September 2023 | December 2029 |
| 17 (LTS) | 17.0.20.1 | Supported | 14 September 2021 | October 2027 |
Spring Boot 4.1.1 needs at least Java 17 and is compatible up to Java 26; the dates are the Eclipse Temurin builds' end of availability, and other JDK vendors publish their own. Java (Eclipse Temurin) release schedule
Minimum secure versions
The lowest release in each supported line that fixes every published advisory listed here. Anything older is missing a security fix.
| Package | At least | Why |
|---|---|---|
org.apache.tomcat.embed:tomcat-embed-core | 11.0.26 | Fixes four Important CVEs (15 September 2026), among them CVE-2026-86350 (HTTP/2 request header mix-up, 11.0.22 to 11.0.25) and CVE-2026-76183 (WebSocket security-constraint bypass). Spring Boot 4.1.1 and 4.0.8 still manage 11.0.24, so set tomcat.version to 11.0.26, as the cards do. Advisory |
org.springframework:spring-webmvc | 7.0.9 | Seven Spring Framework CVEs of 20 August 2026, such as XSS through EscapedErrors (CVE-2026-59281) and SpEL denial of service (CVE-2026-47886); Spring Boot 4.1.1 and 4.0.8 manage it. Advisory |
org.springframework.boot:spring-boot | 4.0.7 (4.0.x) or 4.1.0 | CVE-2026-40976 (Actuator endpoints with no authorization rule) and, from 4.0.7, CVE-2026-41001 and CVE-2026-40992; 4.1.0 shipped with all of them fixed. Advisory |
org.springframework.security | 7.0.7 or 7.1.1 | CVE-2026-47841 (WebAuthn user-verification bypass), CVE-2026-41707 (DPoP proof replay), CVE-2026-47877 (consent-page XSS) and CVE-2026-47842, 20 August 2026; Spring Boot 4.0.8 and 4.1.1 manage it. Advisory |
JDK | 25.0.4.1, 21.0.12.1 or 17.0.20.1 | The 18 August 2026 OpenJDK advisory (CVE-2026-70906, CVE-2026-61308, CVE-2026-70907, CVE-2026-60589) covers 25.0.4, 21.0.12, 17.0.20 and earlier; Temurin ships jdk-25.0.4.1+1 and so on. The next quarterly update was set for 20 October 2026. Advisory |
Middleware and security order
- The filter chain runs in a fixed order:
HeaderWriterFilter,CorsFilter,CsrfFilterandLogoutFiltercome before the authentication filters;ExceptionTranslationFilterandAuthorizationFiltercome last. You choose which filters are on, not their order. - One chain per kind of client: Separate
SecurityFilterChainbeans withsecurityMatcherand@Orderfor the browser app (sessions and CSRF) and the API (bearer tokens, no sessions); put Actuator in its own chain. - Authorization rules, most specific first:
authorizeHttpRequestsuses the first matching rule, so list specific paths first and end withanyRequest().authenticated()ordenyAll(). - Method and object checks:
@EnableMethodSecuritywith@PreAuthorizeon services, and owner-scoped repository queries, so a missed URL rule does not expose data.
Secure defaults and settings
| Setting | Value | Why |
|---|---|---|
| CSRF protection | On for unsafe methods | Keep it for session-based browser apps; a stateless bearer-token API chain can turn it off. |
| Security headers | Cache-Control, X-Content-Type-Options: nosniff, X-Frame-Options: DENY, X-XSS-Protection: 0, HSTS on HTTPS requests | Add a Content-Security-Policy; Spring Security does not set one by default. |
management.endpoints.web.exposure.include | health | Expose more only behind authorization. |
server.servlet.session.cookie.same-site | Not set | Set lax (or strict). |
server.forward-headers-strategy | Not set | Set native or framework behind a proxy so the scheme and client address come from it. |
Escape hatches to search for
Framework APIs that switch a protection off. Each one is sometimes needed; search for them in review and make each use justify itself.
| API | Risk | Instead |
|---|---|---|
csrf(csrf -> csrf.disable()) | Removes CSRF protection from session-authenticated endpoints. | Disable it only in a stateless API chain. |
permitAll() on broad patterns such as /** | Endpoints added later are public. | Default to authenticated() and list public paths. |
@CrossOrigin(origins = "*") or allowedOriginPatterns("*") with credentials | Any site can read authenticated responses. | A list of origins. |
Thymeleaf th:utext | Unescaped output. | th:text, or a sanitizer for HTML you must render. |
management.endpoints.web.exposure.include=* | Exposes heap dumps, environment and other sensitive endpoints. | Expose only what you need, behind authorization. |
Jackson activateDefaultTyping() or @JsonTypeInfo(use = Id.CLASS) | The payload chooses the classes to instantiate. | Concrete types or a closed set of subtypes. |
Checklist, mapped to ASVS 5.0.0
- v5.0.0-8.2.1
authorizeHttpRequestsends with a deny-by-default rule. - v5.0.0-8.2.2 Services check ownership with
@PreAuthorizeor owner-scoped queries. - v5.0.0-3.5.1 CSRF protection stays on in every chain that uses session cookies.
- v5.0.0-13.4.5 Actuator endpoints beyond
healthare not exposed, or need authorization. - v5.0.0-1.2.4 JDBC and JPA queries bind parameters.
- v5.0.0-1.5.1 XML parsers disable DTDs and external entities.
- v5.0.0-15.3.3 Controllers bind request bodies to DTOs that hold only the editable fields.
- v5.0.0-15.2.1 Spring Boot, Spring Framework, Spring Security and Tomcat are at or above the minimum secure versions above.