Wysoka

Spring Data: Unbounded property-path cache keyed by externally-supplied path string

  • Ujawniono: 31.07.2026
  • Aktualizacja: 11.10.2026 13:20

src/main/java/org/springframework/data/mapping/context/PersistentPropertyPathFactory.java:175 · Unbounded Resource Allocation (Algorithmic DoS)

Impact

When a consuming module routes user-supplied dot-paths (sort parameters, projection paths, PATCH paths) through MappingContext.getPersistentPropertyPath(String, Class), each distinct string — including invalid ones — is cached forever. A remote attacker can send millions of requests with unique ?sort=aaaa<n> values and grow the heap until the service OOMs.

Description

PersistentPropertyPathFactory.propertyPaths (line 53) is a ConcurrentHashMap<TypeAndPath, PathResolution> populated by getPotentiallyCachedPath() (line 174-177) via computeIfAbsent. The key is (TypeInformation, rawPathString). Crucially, unresolvable paths are also cached (as PathResolution.unresolved, line 204) so that the same InvalidPersistentPropertyPath can be re-thrown — meaning every distinct garbage string an attacker sends creates a permanent entry. There is no eviction. This is reachable from AbstractMappingContext.getPersistentPropertyPath(String, Class) (AbstractMappingContext.java:345), which Spring Data REST and several store query mappers call with HTTP-request-derived sort/filter property names.

By contrast, the sibling SimplePropertyPath.cache was already hardened to use ConcurrentReferenceHashMap (soft refs); this cache was not given the same treatment.

Exploit scenario

Against a Spring Data REST endpoint, an attacker scripts GET /things?sort=<random-40-char-string> in a loop. Each request fails fast with InvalidPersistentPropertyPath, but each distinct random string leaves behind a TypeAndPath key, a PathResolution object holding the split segments list, and the source string in the map. After ~10M requests the JVM OOMs.

Preconditions

  • A downstream component (Spring Data REST, a store-specific QueryMapper, or application code) passes externally-supplied strings to MappingContext.getPersistentPropertyPath(String, ...)
  • No upstream rate-limiting or path-string validation

How to fix

A cache whose key can be derived from external input must be bounded. Replace propertyPaths (line 53) with a ConcurrentLruCache<TypeAndPath, PathResolution> of fixed capacity, or ConcurrentReferenceHashMap (matching the sibling SimplePropertyPath.cache). Additionally, do not cache PathResolution.unresolved results at all (line 204 in createPersistentPropertyPath) — re-computing a failed lookup is cheap, and caching negative results for arbitrary attacker strings is what makes this exploitable.

Adversarial verification

Verdict: TRUE_POSITIVE (confidence: 7/10) — unbounded hard-ref ConcurrentHashMap keyed by raw path string, caches unresolved entries (line 204), reachable via public MappingContext.getPersistentPropertyPath(String, ...); sibling PropertyPath cache was already converted to soft-refs but this one was missed. -3 confidence because the HTTP-input wiring lives in downstream modules (Spring Data REST / store mappers), not verifiable in this repo.

Code at the line — CONFIRMED

  • Line 53: private final Map<TypeAndPath, PathResolution> propertyPaths = new ConcurrentHashMap<>(); — plain CHM, hard refs, no eviction, no size bound.
  • Line 175: propertyPaths.computeIfAbsent(TypeAndPath.of(type, propertyPath), ...) — every distinct (type, string) pair is inserted.
  • Line 204: return PathResolution.unresolved(parts, segment, type, currentPath); — returned from inside computeIfAbsent's mapping function, so unresolvable paths are cached. The PathResolution retains the full attacker string (source = StringUtils.collectionToDelimitedString(parts, "."), line 452).

Callers within spring-data-commons

  • AbstractMappingContext.getPersistentPropertyPath(String, Class<?>) (line 345) and (String, TypeInformation<?>) (line 350) → persistentPropertyPathFactory.from(type, propertyPath) → straight into the unbounded cache. No validation, no PropertyPath.from gate.
  • This is the public MappingContext interface (MappingContext.java:174,186), documented to throw InvalidPersistentPropertyPath on bad input — i.e., the contract explicitly anticipates being called with possibly-invalid strings.
  • No in-repo caller routes HTTP input directly into the String overload. The Sort.Order.property → getPersistentPropertyPath(String, ...) bridge lives in store modules (Spring Data MongoDB QueryMapper, Spring Data REST sort translator). That wiring is out-of-repo as the finding states.

Protections — NONE on this cache Contrast: SimplePropertyPath.java:52 (the PropertyPath.from cache) uses ConcurrentReferenceHashMap (soft refs, GC-evictable). Spring already hardened the sibling cache against exactly this pattern. PersistentPropertyPathFactory.propertyPaths was not given the same treatment.

Stress-test Is this exclusion #3 (intended design)? The PathResolution javadoc (line 426-430) says caching unresolved paths is deliberate — to make repeated lookups of the same bad path cheap. But unbounded hard-ref caching of arbitrary attacker-chosen keys is not the intent; the sibling fix proves Spring considers this a bug class.

Czego dotyczy

Kliknij technologię, aby zobaczyć wszystkie dotyczące jej podatności.

PlatformaPaczkaPodatne wersjePoprawka w wersji
Java / Kotlin (Maven) org.springframework.data:spring-data-commons >= 4.0.0, < 4.0.6, >= 3.5.0, < 3.5.12, >= 3.4.0, <= 3.4.13 4.0.6, 3.5.12

Odnośniki

Ocena CVSS 7.5/10
Wektor CVSS
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Słabość (CWE)
CWE-400
Platforma
Java / Kotlin (Maven)
Paczka
org.springframework.data:spring-data-commons
Ujawniono
31.07.2026
Aktualizacja
11.10.2026 13:20

Źródła i licencje

OSV / GitHub Advisory Database - GHSA-88fw-v6x4-3f58 - CC BY 4.0

Historia podatności: org.springframework.data:spring-data-commons

Wszystkie opisane podatności tej paczki (Java / Kotlin (Maven)), od najnowszej. Widać, czy to jednorazowa wpadka, czy paczka, której trzeba pilnować.

Wszystkich wpisów
7
Pierwsza → ostatnia
10.2018 07.2026
Bez poprawki
0
Wykorzystywana w atakach
1

Rozkład istotności

  • Krytyczna 1
  • Wysoka 4
  • Średnia 2

Ujawnienia w latach

  1. 2018: 3
  2. 2019: 0
  3. 2020: 0
  4. 2021: 0
  5. 2022: 0
  6. 2023: 0
  7. 2024: 0
  8. 2025: 0
  9. 2026: 4
  1. Spring Data: Unbounded property-path cache keyed by externally-supplied path string ten wpis
    Wysoka · 7.5 CVE-2026-41695 >= 4.0.0, < 4.0.6, >= 3.5.0, < 3.5.12, >= 3.4.0, <= 3.4.13 4.0.6, 3.5.12
  2. Średnia · 5.9 CVE-2026-41721 >= 4.0.0, < 4.0.6, >= 3.5.0, < 3.5.12, >= 3.4.0, <= 3.4.14, >= 3.0.0, <= 3.3.16, <= 2.7.19 4.0.6, 3.5.12
  3. Średnia · 5.9 CVE-2026-41711 >= 4.0.0, < 4.0.6, >= 3.5.0, < 3.5.12, >= 3.4.0, <= 3.4.14, >= 3.0.0, <= 3.3.16, <= 2.7.19 4.0.6, 3.5.12
  4. Wysoka · 7.5 CVE-2026-41716 >= 4.0.0, < 4.0.6, >= 3.5.0, < 3.5.12, >= 3.4.0, <= 3.4.14, >= 3.3.0, <= 3.3.16, <= 2.7.19 4.0.6, 3.5.12
  5. Wysoka · 7.5 CVE-2018-1274 < 1.13.11, >= 2.0.0, < 2.0.6 1.13.11, 2.0.6
  6. Krytyczna · 9.8 Wykorzystywana w atakach CVE-2018-1273 >= 1.13.0, < 1.13.11, >= 2.0.0, < 2.0.6 1.13.11, 2.0.6

Dowiedz się, które podatności dotyczą Twojej aplikacji

Po podłączeniu integracji DockRay i włączeniu raportowania oprogramowania DockRay porównuje zgłoszone wersje komponentów ze znanymi podatnościami i powiadamia o potwierdzonych dopasowaniach. Zakres zależy od obsługiwanej technologii i dostępnych biuletynów.

Podłącz swoją aplikację
Newsletter DockRay

Bezpieczeństwo aplikacji w Twojej skrzynce

Najważniejsze podatności, konkretne zalecenia i praktyczne wskazówki dla Twoich aplikacji. Wybierz technologie i śledź to, co ma znaczenie dla Twojego projektu.

  • Codzienne zestawienie nowych podatności, także krytycznych.
  • Powiadomienia o ważnych aktualizacjach.
  • Praktyczne porady o bezpieczeństwie i monitoringu aplikacji.

Pozostaw puste, aby otrzymywać informacje o wszystkich technologiach.

Zapis jest bezpłatny. Wypiszesz się jednym kliknięciem w wiadomości.