Background
Tier 1 and Tier 2 security hardening was delivered on the Spring Boot 4+ line in releases 4.4.0 (Tier 1) and 5.0.0 / 5.0.1 (Tier 2). The older Spring Boot 3.5 / Java 17 / Spring Security 6 line — last shipped as library 3.5.1 — never received these fixes.
We (the maintainers) no longer run any live apps on Spring Boot 3.x, and we will not add features to or heavily test/maintain the 3.x line. However, this is a public library and there are very likely downstream users still pinned to Spring Boot 3.5 / Java 17 who cannot move to Java 21 / Spring Boot 4 yet. Several of the unpatched issues are genuine vulnerabilities (OAuth account-takeover bypass, brute-force lockout evasion, log injection), so leaving the still-shipped 3.x line unpatched is the wrong posture.
Goal: one final, tightly-scoped security-maintenance release 3.6.0 off the 3.5.1 tag, then declare the 3.x line security-maintenance-only (Java-21 users should move to 5.0.x).
Why the two lines are far apart
The 3.5.1 codebase is much smaller than 4.4.0/5.0.x. Many "fixes" in the 4+ line actually harden features that do not exist at 3.5.1, so they are feature forward-ports, not backports.
|
Library 3.5.1 (3.x line) |
Library 4.4.0 + 5.0.x |
| Spring Boot |
3.5.5 |
4.0 / 4.1 |
| Java |
17 |
21 |
| Spring Security |
6 |
7 |
| Surface present |
OAuth2/OIDC, audit, registration, sessions, LoginAttemptService, UserAPI |
the above plus WebAuthn, MFA, GDPR service, AppUrlResolver, TokenHasher |
Scope decision: minimal, high-confidence subset
Because the 3.x line will not be heavily tested, regression risk is the dominant cost — an under-tested security backport that breaks something is worse than the status quo. So we backport only fixes that are (a) real vulns in code that already exists at 3.5.1, and (b) self-contained enough to verify by reading the diff.
IN SCOPE — backport these (high value ÷ low regression risk)
These map to mostly single-purpose commits on the path to 4.4.0:
| Fix |
Source commit |
Cherry-pick cleanliness |
Atomic brute-force lockout (failed-attempt UPDATE, prevents lockout-evasion race) |
c1a13dc |
Clean — pure JPA/Java, framework-agnostic |
OAuth2 email_verified validation + reject locked/disabled + sanitize failure messages (introduces SanitizingOAuth2AuthenticationFailureHandler) |
4e02429 |
Clean — targeted |
| Reject Facebook OAuth2 login when email explicitly unverified |
a5d8a92 |
Clean — single fix |
Redact secrets/principals in logs + exclude password from toString |
65be92b |
Mostly clean — toString edits touch entities, low risk |
Audit log-forging hardening (strip CR/LF and | in FileAuditLogWriter) |
bundled in 5649436 |
Not separable — that commit also carries token-replay + GDPR atomicity; needs a manual hunk extract of just FileAuditLogWriter |
Cross-line notes:
- Lockout + audit fixes are pure Java/JPA → apply regardless of Security 6 vs 7.
- OAuth fixes (
4e02429, a5d8a92) depend on the OAuth2 user-service API, which is materially the same in Security 6 — expect a compile-check pass, not a guaranteed clean apply.
DEFER / OUT OF SCOPE unless existing 3.5.1 tests already cover the area
Legit fixes, but each carries a real test burden we are choosing not to take on for this line:
- Token replay guard (conditional DELETE-by-token; concurrency — wants racing-thread tests)
- Session-fixation rotation /
SessionRegistry wiring (Security 6 APIs differ; needs auth tests)
- Anti-enumeration uniform 200-vs-409 (behavioral/breaking — needs contract tests updated)
- Registration SERIALIZABLE + unique email constraint (schema change — wants DB tests)
EXPLICITLY OUT OF SCOPE
- Feature forward-ports (not present at 3.5.1): token-at-rest hashing (
TokenHasher), WebAuthn current-password/IDOR/status-code fixes, MFA factor-merging, GDPR deletion atomicity.
- CWE-640 / host-header poisoning via
AppUrlResolver (new component). NOTE: the vulnerability (reset/verification links trusting X-Forwarded-Host) may still exist in the old 3.5.x link-building code. If a quick check shows it does, consider a minimal targeted fix only — not the whole AppUrlResolver machinery.
- All architectural churn from 4.4.0/5.0.0:
@AutoConfiguration migration, ds* bean namespacing, event-payload DTO-ification, entity equals/hashCode, package moves, Passay 2.0, filter-chain coexistence model. Zero security value on a maintenance line; backporting would only destabilize it.
Release shape
- Branch
release/3.6.0 off the 3.5.1 tag.
- Cherry-pick the ~4 in-scope commits + hand-apply the
FileAuditLogWriter sanitization hunk.
- Bump to
3.6.0 (minor, not patch) — even within the in-scope set there may be minor behavioral changes; a minor signals "security-maintenance, review before upgrading."
- CHANGELOG + README note: 3.x line is now security-maintenance-only; Java-21 users should migrate to
5.0.x.
Validation
- Build + test on Java 17 / Spring Boot 3.5.5.
- Run the existing
3.5.1 test suite.
- Validate with the 3.x version of the demo app (boots + Playwright), per our release protocol — not Playwright alone; run the demo's own
./gradlew test against the locally-published 3.6.0-SNAPSHOT.
Acceptance criteria
Background
Tier 1 and Tier 2 security hardening was delivered on the Spring Boot 4+ line in releases 4.4.0 (Tier 1) and 5.0.0 / 5.0.1 (Tier 2). The older Spring Boot 3.5 / Java 17 / Spring Security 6 line — last shipped as library
3.5.1— never received these fixes.We (the maintainers) no longer run any live apps on Spring Boot 3.x, and we will not add features to or heavily test/maintain the 3.x line. However, this is a public library and there are very likely downstream users still pinned to Spring Boot 3.5 / Java 17 who cannot move to Java 21 / Spring Boot 4 yet. Several of the unpatched issues are genuine vulnerabilities (OAuth account-takeover bypass, brute-force lockout evasion, log injection), so leaving the still-shipped 3.x line unpatched is the wrong posture.
Goal: one final, tightly-scoped security-maintenance release
3.6.0off the3.5.1tag, then declare the 3.x line security-maintenance-only (Java-21 users should move to 5.0.x).Why the two lines are far apart
The 3.5.1 codebase is much smaller than 4.4.0/5.0.x. Many "fixes" in the 4+ line actually harden features that do not exist at 3.5.1, so they are feature forward-ports, not backports.
3.5.1(3.x line)4.4.0+5.0.xLoginAttemptService,UserAPIAppUrlResolver,TokenHasherScope decision: minimal, high-confidence subset
Because the 3.x line will not be heavily tested, regression risk is the dominant cost — an under-tested security backport that breaks something is worse than the status quo. So we backport only fixes that are (a) real vulns in code that already exists at 3.5.1, and (b) self-contained enough to verify by reading the diff.
IN SCOPE — backport these (high value ÷ low regression risk)
These map to mostly single-purpose commits on the path to 4.4.0:
UPDATE, prevents lockout-evasion race)c1a13dcemail_verifiedvalidation + reject locked/disabled + sanitize failure messages (introducesSanitizingOAuth2AuthenticationFailureHandler)4e02429a5d8a92toString65be92btoStringedits touch entities, low risk|inFileAuditLogWriter)5649436FileAuditLogWriterCross-line notes:
4e02429,a5d8a92) depend on the OAuth2 user-service API, which is materially the same in Security 6 — expect a compile-check pass, not a guaranteed clean apply.DEFER / OUT OF SCOPE unless existing 3.5.1 tests already cover the area
Legit fixes, but each carries a real test burden we are choosing not to take on for this line:
SessionRegistrywiring (Security 6 APIs differ; needs auth tests)EXPLICITLY OUT OF SCOPE
TokenHasher), WebAuthn current-password/IDOR/status-code fixes, MFA factor-merging, GDPR deletion atomicity.AppUrlResolver(new component). NOTE: the vulnerability (reset/verification links trustingX-Forwarded-Host) may still exist in the old 3.5.x link-building code. If a quick check shows it does, consider a minimal targeted fix only — not the wholeAppUrlResolvermachinery.@AutoConfigurationmigration,ds*bean namespacing, event-payload DTO-ification, entityequals/hashCode, package moves, Passay 2.0, filter-chain coexistence model. Zero security value on a maintenance line; backporting would only destabilize it.Release shape
release/3.6.0off the3.5.1tag.FileAuditLogWritersanitization hunk.3.6.0(minor, not patch) — even within the in-scope set there may be minor behavioral changes; a minor signals "security-maintenance, review before upgrading."5.0.x.Validation
3.5.1test suite../gradlew testagainst the locally-published3.6.0-SNAPSHOT.Acceptance criteria
release/3.6.0branch created off3.5.1c1a13dc)email_verified+ failure-message sanitization backported (4e02429)a5d8a92)65be92b)5649436(FileAuditLogWriter)./gradlew test)3.6.0released