Skip to content
ATR-2026-00448high工具下毒experimental

Spring AI MilvusVectorStore Filter Expression Injection (CVE-2026-41705)

Detects exploitation of CVE-2026-41705 (High), filter-expression injection in Spring AI's MilvusVectorStore. The vulnerable sink concatenates a user/LLM-controlled fragment into a Milvus DSL filter expression passed to MilvusVectorStore.delete() or .similaritySearch() without quoting or parameterisation. Attacker-controlled input breaks out of the intended clause and injects new Milvus DSL operators ( == , in[ , like ), boolean combinators ( or , and ), trailing terminators ( ; -- ), or escape bypasses ( like '%' ESCAPE '\\' ) to broaden the deletion / retrieval scope, exfiltrate or wipe arbitrary collection entries, or bypass access-control filters baked into the original expression. This rule detects the LLM-output / user-input payload shapes that reach the Milvus filter sink: filter-context fields containing unbalanced quotes, Milvus operators combined with boolean chaining, or known filter-bypass primitives. CWE-89, CWE-1287. Patches in Spring AI >= 1.0.0; this rule detects exploit attempts against unpatched deployments and provides defence-in-depth post-patch by catching the injection payload shape regardless of upstream patch state.

嚴重度
high
類別
工具下毒
掃描目標
both
作者
ATR Community

建議回應

block inputalertescalate

參考資料

OWASP Agentic
ASI04:2026 - Memory and Knowledge Base PoisoningASI05:2026 - Unexpected Code Execution
OWASP LLM
LLM05:2025 - Improper Output HandlingLLM08:2025 - Vector and Embedding Weaknesses
MITRE ATLAS
AML.T0051 - LLM Prompt InjectionAML.T0070 - RAG Poisoning

偵測條件

組合方式: any
  1. 01
    Milvus filter field with numeric comparator followed by boolean chain into a tautology (or 1==1, or true, or id==N) — primary CVE-2026-41705 injection shape
    欄位: content運算子: regex
  2. 02
    Filter expression with closing-paren breakout followed by or/and and a fresh Milvus comparator/in-operator — quote-and-paren breakout
    欄位: content運算子: regex
  3. 03
    MilvusVectorStore.delete()/similaritySearch() call whose argument list contains string concatenation — code-level smell that enables CVE-2026-41705
    欄位: content運算子: regex
  4. 04
    Milvus `in[...]` clause followed by or/and boolean chaining into a fresh comparator — injection past the in-clause
    欄位: content運算子: regex
  5. 05
    Filter expression terminated with `;` followed by a destructive verb — classic injection terminator chain
    欄位: content運算子: regex
  6. 06
    Canonical SQL/DSL tautology with sentinel comment-out terminator (-- at EOL or /*) — conservative shape that excludes markdown `#` heading false positives; supports = and == comparator
    欄位: content運算子: regex
  7. 07
    Milvus `like '%' ESCAPE` bypass primitive (supports JSON-escaped quotes around the `%` literal and 0..8 backslash/word chars inside the escape value) — used to defeat literal-character escaping in upstream filter builders
    欄位: content運算子: regex
  8. 08
    Paren-breakout in filter expression followed by AND-chain with new numeric comparator — secondary breakout shape
    欄位: content運算子: regex

攻擊範例(規則會觸發)

  1. {"tool":"MilvusVectorStore.delete","args":{"filter":"id == 1 or 1 == 1"}}
  2. {"tool":"MilvusVectorStore.similaritySearch","args":{"filter":"user_id == \"alice\") or id == 99"}}
  3. milvusVectorStore.delete("id == " + userInput + " or true")
  4. {"filter":"name in [\"x\"] or tenant_id == 99"}
  5. {"filter":"category == \"books\"; DROP TABLE collection"}
  6. ' or 1 == 1 --
  7. filter: "title like \"%\" escape \"\\\\\""
  8. {"filter":"user == \"bob\") and id == 1"}

以上為真實攻擊 payload 脫敏版本。用於 regression testing。

正常樣本(規則不會觸發)

  1. Documentation discussing the patch should not trigger
    The Spring AI 1.0.0 changelog notes that MilvusVectorStore now uses parameterised filter builders to mitigate CVE-2026-41705.
  2. Defensive guidance discussing the mitigation
    Best practice: build Milvus filter expressions via the parameterised builder API instead of string concatenation.
  3. Properly parameterised similarity search using a builder — no concat with user input
    milvusVectorStore.similaritySearch(SearchRequest.builder().query("hello").filter(parameterizedExpr).build())
  4. Discussion of CVE in defensive context
    Reviewing this rule against CVE-2026-41705 to ensure regex coverage is correct.
  5. Single static comparator without boolean chaining or breakout
    filter: "category == \"books\""
  6. Benign English prose mentioning fields and patterns
    The dataset contains records where the title field matches a specific pattern.

已知誤報情境

  • Legitimate documentation or changelog text discussing CVE-2026-41705 patch notes.
  • Static analysis tooling output documenting Milvus filter injection patterns for defensive purposes.
  • Patched Spring AI MilvusVectorStore deployments that use parameterised filter builders.

完整 YAML 定義

在 GitHub 編輯 →
title: "Spring AI MilvusVectorStore Filter Expression Injection (CVE-2026-41705)"
id: ATR-2026-00448
rule_version: 1
status: experimental
description: >
  Detects exploitation of CVE-2026-41705 (High), filter-expression injection
  in Spring AI's MilvusVectorStore. The vulnerable sink concatenates a
  user/LLM-controlled fragment into a Milvus DSL filter expression passed
  to MilvusVectorStore.delete() or .similaritySearch() without quoting or
  parameterisation. Attacker-controlled input breaks out of the intended
  clause and injects new Milvus DSL operators ( == , in[ , like ), boolean
  combinators ( or , and ), trailing terminators ( ;  -- ), or escape
  bypasses ( like '%' ESCAPE '\\' ) to broaden the deletion / retrieval
  scope, exfiltrate or wipe arbitrary collection entries, or bypass
  access-control filters baked into the original expression. This rule
  detects the LLM-output / user-input payload shapes that reach the
  Milvus filter sink: filter-context fields containing unbalanced quotes,
  Milvus operators combined with boolean chaining, or known
  filter-bypass primitives. CWE-89, CWE-1287. Patches in Spring AI
  >= 1.0.0; this rule detects exploit attempts against unpatched
  deployments and provides defence-in-depth post-patch by catching the
  injection payload shape regardless of upstream patch state.
author: "ATR Community"
date: "2026/05/12"
schema_version: "0.1"
detection_tier: pattern
maturity: test
severity: high

references:
  owasp_llm:
    - "LLM05:2025 - Improper Output Handling"
    - "LLM08:2025 - Vector and Embedding Weaknesses"
  owasp_agentic:
    - "ASI04:2026 - Memory and Knowledge Base Poisoning"
    - "ASI05:2026 - Unexpected Code Execution"
  mitre_atlas:
    - "AML.T0051 - LLM Prompt Injection"
    - "AML.T0070 - RAG Poisoning"
  mitre_attack:
    - "T1190 - Exploit Public-Facing Application"
  cve:
    - "CVE-2026-41705"

metadata_provenance:
  mitre_atlas: human-reviewed
  owasp_llm: human-reviewed
  owasp_agentic: human-reviewed
  cve: human-reviewed

compliance:
  eu_ai_act:
    - article: "15"
      context: "CVE-2026-41705 allows unfiltered LLM output to drive Milvus DSL filter construction in Spring AI's MilvusVectorStore; Article 15 cybersecurity requirements mandate that high-risk AI systems parameterise downstream queries instead of concatenating model output into query strings."
      strength: primary
    - article: "9"
      context: "Article 9 risk management must enumerate vector-store filter injection as a high-risk class — the RAG retrieval / deletion path is typically treated as low-risk infrastructure but actually reaches a privileged datastore."
      strength: primary
  nist_ai_rmf:
    - subcategory: "MP.5.1"
      context: "Adversarial inputs that inject Milvus DSL fragments into RAG filter expressions must be tracked as a primary input-attack class affecting vector-store integrations."
      strength: primary
    - subcategory: "MG.2.3"
      context: "Risk treatment plans under MG.2.3 must require parameterised filter construction in any code path that consumes LLM output and reaches a vector-store query / delete API."
      strength: primary
  iso_42001:
    - clause: "8.6"
      context: "Operational controls under clause 8.6 must prohibit LLM-generated or user-supplied content from being string-concatenated into vector-store filter expressions; parameterised filter builders are mandatory."
      strength: primary

tags:
  category: tool-poisoning
  subcategory: vector-store-filter-injection
  scan_target: both
  confidence: high

agent_source:
  type: tool_call
  framework:
    - spring-ai
    - any
  provider:
    - any

detection:
  condition: any
  false_positives:
    - "Legitimate documentation or changelog text discussing CVE-2026-41705 patch notes."
    - "Static analysis tooling output documenting Milvus filter injection patterns for defensive purposes."
    - "Patched Spring AI MilvusVectorStore deployments that use parameterised filter builders."
  conditions:
    - field: content
      operator: regex
      value: '(?i)\b(?:filter|filter_expr|filterExpression)\b[^\n]{0,40}(?:==|!=)\s*\d+[^\n]{0,20}\b(?:or|and)\s+(?:1\s*==\s*1|true\b|\d+\s*==\s*\d+|\w+\s*==\s*\d+)'
      description: "Milvus filter field with numeric comparator followed by boolean chain into a tautology (or 1==1, or true, or id==N) — primary CVE-2026-41705 injection shape"

    - field: content
      operator: regex
      value: '(?i)\b(?:filter|filter_expr|filterExpression)\b[^\n]{0,80}\\?["\x27][^\n]{0,40}\)\s*(?:or|and)\s+\w+\s*(?:==|in\s*\[)'
      description: "Filter expression with closing-paren breakout followed by or/and and a fresh Milvus comparator/in-operator — quote-and-paren breakout"

    - field: content
      operator: regex
      value: '(?i)(?:MilvusVectorStore|milvus[-_]?client|milvus[-_]?service)\b[^.\n]{0,80}\.(?:delete|similaritysearch|similarity_search|search)\s*\([^)\n]{0,200}\+\s*\w'
      description: "MilvusVectorStore.delete()/similaritySearch() call whose argument list contains string concatenation — code-level smell that enables CVE-2026-41705"

    - field: content
      operator: regex
      value: '(?i)\b(?:filter|filter_expr|filterExpression)\b[^\n]{0,40}\bin\s*\[[^\]\n]{0,80}\]\s*(?:or|and)\s+\w+\s*(?:==|!=)'
      description: "Milvus `in[...]` clause followed by or/and boolean chaining into a fresh comparator — injection past the in-clause"

    - field: content
      operator: regex
      value: '(?i)\b(?:filter|filter_expr|filterExpression)\b[^\n]{0,80}["\x27]\s*;\s*(?:drop|delete|truncate|alter)\s+(?:table|from|collection)\b'
      description: "Filter expression terminated with `;` followed by a destructive verb — classic injection terminator chain"

    - field: content
      operator: regex
      value: '(?i)[\x27"]\s+(?:or|and)\s+(?:1\s*=+\s*1|true)\s*(?:--(?=\s|$|["\x27\)])|/\*)'
      description: "Canonical SQL/DSL tautology with sentinel comment-out terminator (-- at EOL or /*) — conservative shape that excludes markdown `#` heading false positives; supports = and == comparator"

    - field: content
      operator: regex
      value: '(?i)\blike\s+\\?["\x27]%\\?["\x27]\s+escape\s+\\?["\x27][\\\\\w]{0,8}\\?["\x27]'
      description: "Milvus `like '%' ESCAPE` bypass primitive (supports JSON-escaped quotes around the `%` literal and 0..8 backslash/word chars inside the escape value) — used to defeat literal-character escaping in upstream filter builders"

    - field: content
      operator: regex
      value: '(?i)\b(?:filter|filter_expr|filterExpression)\b[^\n]{0,80}\)\s+and\s+\w+\s*==\s*\d+'
      description: "Paren-breakout in filter expression followed by AND-chain with new numeric comparator — secondary breakout shape"

response:
  actions:
    - block_input
    - alert
    - escalate
  notify:
    - security_team

remediation: >
  Upgrade Spring AI to >= 1.0.0. Replace string-concatenated Milvus filter
  expressions with parameterised filter builders; never interpolate LLM
  output or user input directly into filter strings passed to
  MilvusVectorStore.delete() or .similaritySearch(). Validate filter
  fragments against an allowlist of operators / field names before
  building the final expression. Treat LLM output as untrusted input
  from a security perspective.

test_cases:
  true_positives:
    - input: '{"tool":"MilvusVectorStore.delete","args":{"filter":"id == 1 or 1 == 1"}}'
      expected: triggered
      description: "Tautology-based deletion-broadening injection — CVE-2026-41705 canonical shape"
    - input: '{"tool":"MilvusVectorStore.similaritySearch","args":{"filter":"user_id == \"alice\") or id == 99"}}'
      expected: triggered
      description: "Closing-paren breakout followed by or chaining with comparator"
    - input: 'milvusVectorStore.delete("id == " + userInput + " or true")'
      expected: triggered
      description: "Source-level concat against Milvus delete sink — code path that enables CVE-2026-41705"
    - input: '{"filter":"name in [\"x\"] or tenant_id == 99"}'
      expected: triggered
      description: "in-operator followed by or chaining with new comparator — bypass of original access-control filter"
    - input: '{"filter":"category == \"books\"; DROP TABLE collection"}'
      expected: triggered
      description: "Filter terminator + destructive verb — classic injection chain"
    - input: "' or 1 == 1 --"
      expected: triggered
      description: "Canonical tautology + comment-out payload pasted into the user_input field"
    - input: 'filter: "title like \"%\" escape \"\\\\\""'
      expected: triggered
      description: "Milvus like-escape bypass primitive"
    - input: '{"filter":"user == \"bob\") and id == 1"}'
      expected: triggered
      description: "Paren-breakout into AND-chain with new comparator"
  true_negatives:
    - input: "The Spring AI 1.0.0 changelog notes that MilvusVectorStore now uses parameterised filter builders to mitigate CVE-2026-41705."
      expected: not_triggered
      description: "Documentation discussing the patch should not trigger"
    - input: "Best practice: build Milvus filter expressions via the parameterised builder API instead of string concatenation."
      expected: not_triggered
      description: "Defensive guidance discussing the mitigation"
    - input: 'milvusVectorStore.similaritySearch(SearchRequest.builder().query("hello").filter(parameterizedExpr).build())'
      expected: not_triggered
      description: "Properly parameterised similarity search using a builder — no concat with user input"
    - input: "Reviewing this rule against CVE-2026-41705 to ensure regex coverage is correct."
      expected: not_triggered
      description: "Discussion of CVE in defensive context"
    - input: 'filter: "category == \"books\""'
      expected: not_triggered
      description: "Single static comparator without boolean chaining or breakout"
    - input: "The dataset contains records where the title field matches a specific pattern."
      expected: not_triggered
      description: "Benign English prose mentioning fields and patterns"

修訂歷史

建立於
2026-05-12
最後修改
2026-05-12
在 GitHub 查看完整 commit 歷史 →