Files
rag/docs/代码审查报告_2026-06-05.md
2026-06-05 15:26:38 +08:00

8.5 KiB
Raw Blame History

RAG-Agent 代码审查报告(精简版)

审查日期2026-06-05

排除说明storage 模块尚未启用(暂不纳入);用户认证/权限由后端服务负责(生产环境 RAG 服务为无状态接口,不做鉴权)。


一、高危问题6 项)

H1. SSE 错误事件泄露完整堆栈信息

  • 文件:api/chat_routes.py:1955
  • /rag 接口 SSE 生成器在异常时将 traceback.format_exc() 完整堆栈直接发给客户端,暴露调用栈、文件路径、代码行号、内部变量。
  • 修复:移除 traceback 字段,仅在服务端日志记录,客户端返回通用错误消息。

H2. 文档更新/删除接口存在路径遍历风险

  • 文件:api/document_routes.py:652,714
  • update_documentdelete_document 直接将 URL 中的 doc_path 拼接到文件路径,未做安全校验。可构造 ../../ 路径遍历载荷。
  • 修复:使用 os.path.realpath() 解析最终路径,验证是否在 DOCUMENTS_PATH 目录下。

H3. serve_document_file 路径遍历风险

  • 文件:api/document_routes.py:139
  • 文件服务接口同样存在路径遍历风险。虽然有 DEV_MODE 开关,但默认值为 'true'
  • 修复:添加 realpath 校验。

H4. 文档更新接口缺少文件类型和大小校验

  • 文件:api/document_routes.py:621
  • update_document (PUT) 未验证文件类型和大小,直接 file.save(filepath)。与之对比,upload_document 有完整校验。
  • 修复:添加与 upload 一致的 ALLOWED_EXTENSIONS 和 MAX_FILE_SIZE 校验。

H5. 批量上传接口缺少文件大小校验

  • 文件:api/document_routes.py:350
  • batch_upload_documents 对每个文件只检查了扩展名,未检查文件大小。可批量上传超大文件导致磁盘耗尽。
  • 修复:在循环内添加 MAX_FILE_SIZE 校验。

H6. main.py debug 模式默认开启 + 监听 0.0.0.0

  • 文件:main.py:29-31
  • --debug 默认 True--host 默认 0.0.0.0。Flask 调试模式启用 Werkzeug 交互式 debugger可通过触发异常执行任意代码。
  • 修复:--debug 默认值改为 False

二、中危问题13 项)

M1. 多处异常响应直接暴露内部错误信息

  • 文件:document_routes.py:332,467,733kb_routes.py:523,636feedback_routes.py:98,116sync_routes.py:119audit_routes.py:100 等。
  • 大量 except 块直接 str(e) 返回给客户端可能包含数据库路径、SQL 片段、文件系统结构。
  • 修复:统一使用通用错误消息,原始异常仅记录到服务端日志。

M2. /search 接口缺少输入安全验证

  • 文件:api/chat_routes.py:1974
  • 未调用 validate_query() 做注入检测和长度限制,与 /chat/rag 不一致。
  • 修复:添加 validate_query(query) 调用。

M3. /searchtop_k 参数未校验范围

  • 文件:api/chat_routes.py:1989
  • 可传 top_k=999999 导致内存溢出。
  • 修复:top_k = max(1, min(int(top_k), 50))

M4. context_count 参数未校验范围

  • 文件:api/document_routes.py:821
  • 未限制范围且非整数字符串会 ValueError 导致 500。
  • 修复try/except + max(0, min(n, 10))

M5. CORS 配置允许所有来源

  • 文件:api/__init__.py:70
  • CORS(app) 默认允许 * 跨域。生产环境应限制为已知前端域名。
  • 修复:根据 APP_ENV 条件配置 origins。

M6. LIKE 通配符注入风险

  • 文件:api/kb_routes.py:503
  • kb_name%_ 时会导致非预期的 LIKE 匹配行为。
  • 修复:对 LIKE 特殊字符转义后再拼入模式。

M7. SESSION_MANAGER 为 None 时未处理

  • 文件:api/session_routes.py:35,64,83,102
  • 初始化失败时 SESSION_MANAGER 为 None调用方法会触发 AttributeError 导致 500。
  • 修复:使用前检查 None返回 503。

M8. LLM 调用缺少统一的超时和重试机制

  • 文件:core/llm_utils.py
  • 部分 LLM 调用无超时控制,长时间阻塞会耗尽 worker。@retry 装饰器只在部分方法上使用。
  • 修复:在 _call_llm 层面统一超时和重试。

M9. LLM 输出 JSON 解析不够健壮

  • 文件:core/agentic.pycore/agentic_answer.pycore/agentic_quality.py
  • 多处 LLM 返回的 JSON 解析缺少多策略提取和重试,仅靠 prompt 约束。exam_pkg 已修复但 core 模块尚未统一。
  • 修复:提取 exam_pkg 的 _extract_json 为公共工具core 模块统一使用。

M10. Prompt 注入风险

  • 文件:core/engine.py:2017core/agentic_answer.py:83
  • 用户输入直接拼入 prompt未做净化。恶意输入可操控 LLM 输出。
  • 修复:对用户输入做基本的 prompt 注入检测(如检测 "ignore previous instructions" 等模式)。

M11. subprocess.run 命令参数注入风险

  • 文件:parsers/mineru_parser.py:632
  • file_path 中特殊字符(如以 - 开头的文件名)可能被命令行工具解释为选项。
  • 修复:在文件路径前插入 -- 分隔符;对 backend、lang 参数做白名单校验。

M12. Excel/文本解析器无文件大小限制

  • 文件:parsers/excel_parser.py:81parsers/txt_parser.py:15
  • 一次性加载全文件到内存,超大文件导致 OOM。
  • 修复:解析前检查文件大小,设定上限(如 50MB

M13. 全局变量缓存竞态条件

  • 文件:api/document_routes.py:100api/kb_routes.py:46
  • 模块级全局变量 _kb_manager 等在多线程 gunicorn 下存在竞态。
  • 修复:使用 threading.Lock 保护或改用 flask.current_app.config

三、低危问题12 项)

L1. config.py 硬编码第三方 API 端点 xiaomimimo.com 作为默认值(第 20 行)— 改为空字符串,要求环境变量显式配置。

L2. python-dotenv 未安装时静默跳过,服务可能 fail-open 启动(config.py:11)— 生产环境缺失时抛异常。

L3. assert 校验可被 python -O 跳过(api/__init__.py:236)— 改为 raise ValueError

L4. /chathistory 未限长度(chat_routes.py:1247)— 可消耗大量 token。

L5. history 元素结构未验证(chat_routes.py:1117)— 缺少字段时 KeyError 导致 500。

L6. safe_filename 运算符优先级不明确(document_routes.py:94)— 加括号明确。

L7. DocStore glob 模式未转义特殊字符(document_routes.py:267)— 用 glob.escape()

L8. 相对路径 .data/images 因工作目录不同可能解析错误(chat_routes.py:59)— 改用 PROJECT_ROOT 绝对路径。

L9. asyncio.run() 在 Flask 请求上下文中兼容性问题(chat_routes.py:1744)。

L10. Excel 同一文件被重复读取多次(excel_parser.py:81,89)— 应复用 ExcelFile 对象。

L11. PDF 图片提取 doc 对象异常时未关闭(image_extractor.py:78)— 改用 with 语句。

L12. TXT 解析器异常用 print 而非 loggertxt_parser.py:26)。


四、修复优先级

按修复成本从低到高排序:

第一批:快速修复(半天,改几行代码)

编号 问题 改动量
H6 main.py debug 默认开启 1 行
M3 /search top_k 范围校验 2 行
M2 /search 加 validate_query 2 行
M4 context_count 范围校验 3 行
L3 assert 改 raise 3 行
H1 SSE 移除 traceback 字段 5 行

第二批安全加固1-2 天)

编号 问题 改动量
H2+H3 文档接口路径遍历 realpath 校验 ~30 行
H4+H5 文档更新/批量上传加文件校验 ~30 行
M6 LIKE 通配符转义 ~10 行
M1 异常信息统一脱敏 多文件,每处 2-3 行
M5 CORS 生产环境限制来源 ~5 行
M7 SESSION_MANAGER None 保护 ~10 行
M11 subprocess 参数注入防护 ~5 行

第三批架构改进1-2 周)

编号 问题 说明
M8+M9 LLM 调用统一超时/重试/解析 提取 exam_pkg 经验为公共工具
M10 Prompt 注入防御 需设计检测规则
M13 全局变量竞态修复 threading.Lock
M12 解析器文件大小限制 统一加前置校验

五、做得好的方面

SQL 查询全部使用参数化查询,无注入风险;validate_query() 对聊天输入做了注入检测和违禁词过滤;safe_filename 对上传文件做了基本防护;filter_response() 能过滤 API 密钥等敏感信息exam_pkg 的输入校验体系完整(已在本轮开发中加固);.gitignore 正确排除了 .env 等敏感文件。