# Spring Framework — CWE-407 Disclosure Brief **2026-04-13 · Patches available — awaiting upstream merge** ## Finding Three O(n²) defects in Spring Framework across CORS header validation, locale resolution, and static resource encoding negotiation. All patched. Patches ready for upstream review. All three defects fire on every HTTP request that hits the affected path. ## The Defects **spring-framework-0001 (PATCHED — HIGH):** `spring-web/.../CorsConfiguration.java:724` ```java // In checkHeaders() — fires per CORS preflight/actual request: for (String allowedHeader : this.allowedHeaders) { if (requestHeader.equalsIgnoreCase(allowedHeader)) { result.add(requestHeader); break; } } ``` `allowedHeaders` stores permitted CORS headers as an `ArrayList`. `checkHeaders()` iterates request headers (R) and for each scans the entire allowed headers list (A) with case-insensitive comparison. Total: O(R×A) per request. Fires on every CORS-enabled endpoint. **spring-framework-0002 (PATCHED — MEDIUM):** `spring-webmvc/.../AcceptHeaderLocaleResolver.java:103` and `spring-web/.../AcceptHeaderLocaleContextResolver.java:114` ```java // In findSupportedLocale() — fires per request with Accept-Language header: if (supportedLocales.contains(locale)) { // ... } ``` `supportedLocales` stores configured locales as an `ArrayList`. `contains()` does O(S) linear scan for every request locale from the `Accept-Language` header. Total: O(R×S) per request. Present in both the servlet and reactive WebFlux variants. **spring-framework-0003 (PATCHED — MEDIUM):** `spring-webmvc/.../EncodedResourceResolver.java:66` and `spring-webflux/.../EncodedResourceResolver.java:67` ```java // In resolveResource() — fires per static resource request: private final List contentCodings = new ArrayList<>(DEFAULT_CODINGS); // ... later, per accepted encoding: if (contentCodings.contains(coding)) { ... } ``` `contentCodings` stores supported compression encodings (br, gzip) as an `ArrayList`. For each `Accept-Encoding` token in the request, `contains()` scans the list — O(A×C) per static resource request. Present in both servlet and reactive variants. ## Complexity Proof **spring-framework-0001:** At R=20 request headers, A=30 allowed headers: - Defective: 20 × 30 = 600 case-insensitive comparisons per request - Fixed: 20 × 1 = 20 set lookups (LinkedHashSet) - **30× op reduction per request.** At 10,000 req/s = 6,000,000 → 200,000 comparisons/s. **spring-framework-0002:** At R=10 Accept-Language locales, S=20 supported locales: - Defective: 10 × 20 = 200 comparisons per request - Fixed: 10 × 1 = 10 set lookups (LinkedHashSet) - **20× op reduction per request.** **spring-framework-0003:** At A=5 accepted encodings, C=3 content codings: - Defective: 5 × 3 = 15 comparisons per request - Fixed: 5 × 1 = 5 set lookups (LinkedHashSet) - **3× op reduction per request.** Lower ratio but fires on every static resource request. ## Impact Spring Framework powers millions of Java web applications worldwide — the dominant server-side Java framework. spring-framework-0001 fires on every CORS-enabled endpoint, which includes most modern APIs serving browser clients. At scale (thousands of requests per second with many allowed headers), the quadratic scan consumes measurable CPU. spring-framework-0002 fires on every request with an `Accept-Language` header when locale resolution uses the default `AcceptHeaderLocaleResolver` — virtually every internationalized application. spring-framework-0003 fires on every static resource request when content encoding negotiation activates. ## The Fix **spring-framework-0001:** Build a `LinkedHashSet` (case-folded to lowercase) from `allowedHeaders` at the start of `checkHeaders()`. Replace the inner loop with a single `allowedSet.contains(requestHeader.toLowerCase())` call. ```java // Before for (String allowedHeader : this.allowedHeaders) { if (requestHeader.equalsIgnoreCase(allowedHeader)) { ... } } // After — O(1) per header Set allowedSet = new LinkedHashSet<>(); for (String h : this.allowedHeaders) { allowedSet.add(h.toLowerCase(Locale.ROOT)); } if (allowedSet.contains(requestHeader.toLowerCase(Locale.ROOT))) { ... } ``` **spring-framework-0002:** Maintain a `LinkedHashSet` alongside the `supportedLocales` list. Replace `supportedLocales.contains(locale)` with `supportedSet.contains(locale)`. **spring-framework-0003:** Change `contentCodings` from `ArrayList` to `LinkedHashSet` for O(1) `contains()`. ## Patch Fixes available: - `defects/spring-framework/patch/spring-framework-0001-cors-check-headers-o-r-a.patch` - `defects/spring-framework/patch/spring-framework-0002-accept-language-locale-o-r-s.patch` - `defects/spring-framework/patch/spring-framework-0003-encoded-resource-resolver-content-codings-o-a-c.patch` Three patches across `CorsConfiguration.java`, `AcceptHeaderLocaleResolver.java`, `AcceptHeaderLocaleContextResolver.java`, and `EncodedResourceResolver.java` (both servlet and reactive variants). ## What We Ask Patches ready for review. 1. Confirm receipt and assign a GitHub issue reference (spring-projects/spring-framework). 2. Assess severity — spring-framework-0001 fires on every CORS request; spring-framework-0002 fires on every localized request; spring-framework-0003 fires on every encoded static resource request. 3. Coordinate a disclosure date — we target 90 days from first contact. 4. We will credit the Spring team in the public disclosure. Preferred acknowledgment format welcome. Contact: see cover email. This brief is confidential until coordinated disclosure.