Skip to content

Backport critical security fixes to the Spring Boot 3.5.x (3.x) line as a final security-maintenance release (3.6.0) #322

@devondragon

Description

@devondragon

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

  • release/3.6.0 branch created off 3.5.1
  • Atomic brute-force lockout backported (c1a13dc)
  • OAuth2 email_verified + failure-message sanitization backported (4e02429)
  • Facebook explicit-unverified rejection backported (a5d8a92)
  • Secret/principal log redaction backported (65be92b)
  • Audit log-forging hunk hand-applied from 5649436 (FileAuditLogWriter)
  • Quick check whether the 3.5.x reset/verification link path is CWE-640-vulnerable; targeted fix only if so
  • Library builds + tests pass on Java 17 / Spring Boot 3.5.5
  • Validated against the 3.x demo app (boot + Playwright + demo ./gradlew test)
  • CHANGELOG + README updated; 3.x marked security-maintenance-only
  • 3.6.0 released

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions