Status: Source-grounded review of public advisories and code, checked on September 24, 2026. The local validation described below is proposed and has not been independently run.
A metadata filter can look like a search convenience while carrying the entire access-control decision. Consider a document assistant that searches a shared index and adds a tenant condition before sending retrieved text to a model. If converting that condition changes its meaning, the model receives documents that should never have crossed the retrieval boundary. An instruction telling the model to respect confidentiality arrives too late.
CVE-2026-22729 provides a concrete reason to inspect that conversion. Spring published the advisory on March 17, 2026, describing unescaped user-controlled filter values in AbstractFilterExpressionConverter and possible access to unauthorized documents. Its prose describes authenticated users and applications relying on metadata filters for access restrictions. Those conditions matter more to an application review than the presence of a vector database alone. Spring advisory
Establish the version facts first
The advisory identifies these release boundaries:
| Spring AI line | Affected releases listed | Fixed release listed |
|---|---|---|
| 1.0 | 1.0.0–1.0.3 | 1.0.4 |
| 1.1 | 1.1.0–1.1.2 | 1.1.3 |
These are the fixes named for this CVE, not a claim that they are the newest available releases in September. Spring’s release announcement also states that 2.0.0-M3 includes the fix; that milestone statement does not establish an affected range for every earlier 2.0 prerelease. March 17 release announcement
For a deployed service, record the resolved runtime artifacts, not only the version declared in a parent build file. Dependency overrides, an old application image, or a locally modified converter can make the nominal upgrade differ from the running code. A useful remediation ticket names the artifact, its resolved version, the deployment digest, and the converter actually used by the retrieval path.
Follow the value across language boundaries
Spring AI exposes portable metadata filters through text expressions and a programmatic expression builder. The PGvector documentation explains that these expressions become PostgreSQL JSONPath expressions. Consequently, a Java value eventually acquires meaning inside another language. The structured API is an intermediate representation; its safety depends on the serializer preserving the distinction between values and grammar. PGvector reference
An application may intend the following policy composition. This is an illustrative boundary sketch, not a complete application:
// trustedPrincipal comes from validated server-side authentication. |
The tenant identifier expresses authority. The requested category expresses a preference that may narrow the result set. Neither should grant the caller the ability to rewrite the surrounding predicate. A reviewer should therefore trace the category through request parsing, builder construction, converter selection, generated query text, database evaluation, and returned document identifiers.
The pre-fix v1.1.2 base converter makes the failure understandable. Its default string handling wraps a value in double quotes using formatting, without an intervening escaping operation. Adding delimiters does not ensure that delimiters inside the value remain data. This observation is directly visible in the source; the resulting access-control impact is described by the advisory. Pre-fix converter source
The architectural inference is broader: parameterizing an outer SQL statement would not automatically validate the semantics of an embedded query language. Review each parser boundary separately. The relevant question is whether the innermost interpreter receives a literal value or additional executable query structure.
Read the patch as a contract change
The release-linked commit 5b6723811ba932b2af851355384e07caecdd904f removes the base class’s generic doSingleValue implementation and makes the method abstract. It introduces helpers for JSON serialization and Lucene string escaping. The JSON helper delegates to Jackson’s writeValueAsString, while subclasses become responsible for choosing appropriate value formatting. Converter patch
That design change matters because “escape a string” is incomplete without naming the target grammar. A JSON literal, a Lucene query component, and a database-specific expression do not share one universal encoding rule. This interpretation follows from the division of responsibilities in the patch; it is not a claim that every changed backend had the same exposure.
The v1.1.3 PGvector converter implements doSingleValue using the JSON helper, with a separate date conversion path. Its list processing also passes elements through date normalization. The same file still emits keys through a distinct doKey method, illustrating why a value-handling fix should not be generalized into permission to accept arbitrary client-selected keys or complete expressions. That is a review boundary, not a claim of another vulnerability. Fixed PGvector converter
Validate policy semantics with a small local fixture
A proposed regression should start with two synthetic tenants and a handful of documents whose ownership is unambiguous. Give each tenant an ordinary document and one with punctuation in an allowed category value. Keep embeddings deterministic, use a sufficiently small fixture, and choose search settings that allow the expected document to appear. Otherwise, approximate retrieval or a similarity threshold can make an isolation test pass simply by returning nothing.
The central assertion is about returned identifiers and ownership, before any model response is generated:
for every returned document: |
| Proposed case | Property to inspect | Evidence to retain |
|---|---|---|
| Ordinary category value | Valid filtering still retrieves the control document | Expected and actual IDs |
| Quote or backslash within a legitimate label | The value remains one literal | Converter output and result IDs |
| List containing ordinary and punctuated labels | Every element preserves its value | Expected membership and result IDs |
| Missing or invalid tenant context | Retrieval fails closed | Decision event and zero returned documents |
| Request names a different tenant | Server authority remains controlling | Trusted tenant and effective filter structure |
Run converter-level checks separately from database integration checks. A string comparison can detect a serialization change, but only execution against the chosen backend tests its interpretation there. Conversely, a database test may miss a converter branch if its fixture never exercises lists or typed values. The table describes coverage to implement, not measured outcomes.
For comparison, retain an isolated pre-fix dependency profile and a fixed profile with otherwise identical fixtures. Ordinary punctuation provides a useful serialization regression without turning the exercise into an exploit recipe. It does not, by itself, demonstrate the advisory’s full impact. Record that distinction explicitly in the report.
Close the remediation with bounded claims
A convincing closure package contains the resolved dependency evidence, the reachable converter path, the policy assertions, and the regression results once actually executed. Include custom subclasses and fallback retrieval paths in the review: an application can still construct an unsafe raw expression outside the corrected library path.
Keep authorization checks tied to trusted identity, restrict caller-selectable filter fields and operators, and ensure caches cannot reuse one tenant’s retrieval results for another. Those are application design recommendations, not additional conditions stated by the CVE advisory. Database-enforced separation may provide another boundary, but it requires its own configuration and tests.
The patch addresses a particular conversion defect. A defensible application-level claim is narrower than “RAG is secure”: the deployed dependency contains the fix, the intended path uses it, and the tested retrieval operations preserve the declared tenant policy. That claim is specific enough to verify again when the index, converter, or retrieval architecture changes.