Skip to content

fix(search): sanitize FTS5 query input#396

Open
drive888 wants to merge 1 commit into
TencentCloud:mainfrom
drive888:fix-160-fts5-sanitize
Open

fix(search): sanitize FTS5 query input#396
drive888 wants to merge 1 commit into
TencentCloud:mainfrom
drive888:fix-160-fts5-sanitize

Conversation

@drive888

@drive888 drive888 commented Jul 4, 2026

Copy link
Copy Markdown

变更说明

修复 buildFtsQuery() 未在分词前清理 FTS5 查询语法的问题,避免用户输入中的 AND / OR / NOT / NEAR 等操作符影响 MATCH 查询语义。

问题原因

buildFtsQuery() 会把用户输入分词后用 OR 拼成 FTS5 查询。虽然每个 token 会被双引号包裹,但原始输入在进入 jieba 或 fallback regex 分词前没有显式清理 FTS5 操作符,存在 defense-in-depth 缺口。

主要修改

  • buildFtsQuery() 分词前清理 AND / OR / NOT / NEAR / NEAR/n
  • 清理 FTS5 控制字符,避免用户输入改变查询结构
  • 在 jieba 路径和 fallback regex 路径中都使用清理后的输入
  • 增加 token 级过滤,防止 tokenizer 输出 FTS5 操作符
  • 保留普通搜索词,例如 ANDROIDordinary、中文查询和 API 关键词
  • 保留 SQLite prepared statement 参数传入方式,并在查询构造前增加 token 白名单式清洗
  • 补充 CHANGELOG.md

Recall 一致性验证

为确认清洗逻辑不会影响正常召回效果,新增真实 SQLite FTS 召回对比测试。

测试方式:

  1. 创建临时 SQLite VectorStore
  2. 写入多条 L1 memory:
    • mem-1: memory sqlite user preference
    • mem-2: 旅行计划 API TypeScript
    • mem-3: ANDROID scanner ordinary nearby
    • mem-4: project issue recall screenshot comparison
  3. 对同一批 raw query,分别使用:
    • 旧逻辑 legacyQuery
    • 新逻辑 sanitizedQuery
  4. 分别调用真实 searchL1Fts() 查询 SQLite FTS
  5. 对比两边返回的 record_idcontent

覆盖 query:

  • memory sqlite user preference
  • 旅行计划 API TypeScript
  • ANDROID scanner ordinary nearby
  • project recall screenshot comparison
  • memory AND sqlite NEAR/3 user "preference"*

验证结果:

  • 普通英文 query:旧逻辑和新逻辑召回一致
  • 中文 + API 混合 query:旧逻辑和新逻辑召回一致
  • 包含 operator 子串的普通词,例如 ANDROID / ordinary:未被误删,召回一致
  • 带 FTS5 语法噪声的 query:新逻辑会清理 AND / NEAR/3 / 引号 / *,但真实召回结果仍与旧逻辑一致

真实输出中可以看到每组 query 都打印了:

  • legacyQuery
  • sanitizedQuery
  • legacyRecall
  • sanitizedRecall

其中 legacyRecallsanitizedRecallid/content 完全一致,确认清洗后没有造成正常召回退化。

部分测试截图:
image
image

测试

  • npm test -- src/core/store/sqlite.test.ts --reporter=verbose
    • 1 test file passed
    • 8 tests passed
    • 输出包含 FTS recall parity: legacy vs sanitized 的真实召回对比
  • npm test
    • 5 test files passed
    • 75 tests passed
  • npm run build:plugin
    • build passed

关联 Issue

Closes #160

Signed-off-by: drive888 <2085696241@qq.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(search): buildFtsQuery does not sanitize FTS5 operators — user input alters query semantics

1 participant