VYPR
High severity7.5NVD Advisory· Published Mar 27, 2026· Updated Apr 16, 2026

CVE-2026-22743

CVE-2026-22743

Description

Spring AI's spring-ai-neo4j-store contains a Cypher injection vulnerability in Neo4jVectorFilterExpressionConverter. When a user-controlled string is passed as a filter expression key in Neo4jVectorFilterExpressionConverter of spring-ai-neo4j-store, doKey() embeds the key into a backtick-delimited Cypher property accessor (node.metadata.) after stripping only double quotes, without escaping embedded backticks.This issue affects Spring AI: from 1.0.0 before 1.0.5, from 1.1.0 before 1.1.4.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.springframework.ai:spring-ai-neo4j-storeMaven
>= 1.0.0-M5, < 1.0.51.0.5
org.springframework.ai:spring-ai-neo4j-storeMaven
>= 1.1.0-M1, < 1.1.41.1.4

Affected products

1
  • cpe:2.3:a:vmware:spring_ai:*:*:*:*:*:*:*:*
    Range: >=1.0.0,<1.0.5

Patches

1
3a46c7dd00e4

fix: Neo4jVectorFilterExpressionConverter key handling

https://github.com/spring-projects/spring-aiIlayaperumal GopinathanMar 19, 2026via ghsa
2 files changed · +36 2
  • vector-stores/spring-ai-neo4j-store/src/main/java/org/springframework/ai/vectorstore/neo4j/filter/Neo4jVectorFilterExpressionConverter.java+7 1 modified
    @@ -16,6 +16,8 @@
     
     package org.springframework.ai.vectorstore.neo4j.filter;
     
    +import org.neo4j.cypherdsl.support.schema_name.SchemaNames;
    +
     import org.springframework.ai.vectorstore.filter.Filter;
     import org.springframework.ai.vectorstore.filter.Filter.Expression;
     import org.springframework.ai.vectorstore.filter.Filter.Group;
    @@ -76,7 +78,11 @@ protected void doNot(Expression expression, StringBuilder context) {
     
     	@Override
     	protected void doKey(Key key, StringBuilder context) {
    -		context.append("node.").append("`metadata.").append(key.key().replace("\"", "")).append("`");
    +		String sanitized = SchemaNames.sanitize("metadata." + key.key(), true)
    +			.orElseThrow(() -> new IllegalArgumentException(
    +					"Invalid or empty metadata key cannot be used in a Neo4j filter expression: '%s'"
    +						.formatted(key.key())));
    +		context.append("node.").append(sanitized);
     	}
     
     	@Override
    
  • vector-stores/spring-ai-neo4j-store/src/test/java/org/springframework/ai/vectorstore/neo4j/filter/Neo4jVectorFilterExpressionConverterTests.java+29 1 modified
    @@ -126,7 +126,7 @@ public void testDecimal() {
     	@Test
     	public void testComplexIdentifiers() {
     		String vectorExpr = this.converter
    -			.convertExpression(new Expression(EQ, new Key("\"country 1 2 3\""), new Value("BG")));
    +			.convertExpression(new Expression(EQ, new Key("country 1 2 3"), new Value("BG")));
     		assertThat(vectorExpr).isEqualTo("node.`metadata.country 1 2 3` = \"BG\"");
     	}
     
    @@ -139,6 +139,13 @@ public void testComplexIdentifiers2() {
     			.isEqualTo("node.`metadata.author` IN [\"john\",\"jill\"] AND node.`metadata.article_type` = \"blog\"");
     	}
     
    +	@Test
    +	public void testComplexIdentifiers3() {
    +		String vectorExpr = this.converter
    +			.convertExpression(new Expression(EQ, new Key("\"country 1 2 3\""), new Value("BG")));
    +		assertThat(vectorExpr).isEqualTo("node.`metadata.\"country 1 2 3\"` = \"BG\"");
    +	}
    +
     	@Test
     	public void testEmptyList() {
     		// category IN []
    @@ -250,4 +257,25 @@ public void testNegativeNumbers() {
     		assertThat(vectorExpr).isEqualTo("node.`metadata.valueA` <= -5 AND node.`metadata.valueB` >= -10");
     	}
     
    +	@Test
    +	public void testKeyWithBacktick() {
    +		String vectorExpr = this.converter
    +			.convertExpression(new Expression(EQ, new Key("a` IS NOT NULL WITH node, score //"), new Value("v")));
    +		assertThat(vectorExpr).isEqualTo("node.`metadata.a`` IS NOT NULL WITH node, score //` = \"v\"");
    +	}
    +
    +	@Test
    +	public void testKeyFromTextParser() {
    +		Expression expr = new FilterExpressionTextParser().parse("\"safe_key\" == 'value'");
    +		String vectorExpr = this.converter.convertExpression(expr);
    +		assertThat(vectorExpr).isEqualTo("node.`metadata.safe_key` = \"value\"");
    +	}
    +
    +	@Test
    +	public void testKeyWithControlCharacters() {
    +		String vectorExpr = this.converter
    +			.convertExpression(new Expression(EQ, new Key("key\nwith\nnewline"), new Value("v")));
    +		assertThat(vectorExpr).isEqualTo("node.`metadata.key\nwith\nnewline` = \"v\"");
    +	}
    +
     }
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

6

News mentions

0

No linked articles in our index yet.