【Bug已解决】Filesystem file search rejects valid path segments containing double dots 【Bug已解决】Filesystem file search rejects valid path segments containing double dots一、现象长什么样某文件系统的文件搜索工具比如 agent 用来在目录里找文件的FileSystem工具带一个防路径穿越path traversal的保护拒绝任何包含..的路径防止用户/模型读到上级目录。但这个保护过激了——它把路径里出现..子串一律拒绝连合法的、非穿越的..用法也挡掉了以..开头的隐藏文件如..bashrc少见但合法、..hidden。文件名中间含连续两点如report..final.md、a..b.txt、v1..2用户用..当分隔符。某些工具把..用于相对上移以外语义比如版本或命名约定。结果用户明明要搜一个就叫report..final.md的文件工具直接ValueError: path traversal detected拒绝明明没有穿越意图。过度防御变成了功能缺陷。二、背景路径穿越防护的标准写法是解析路径后检查是否有段等于..即os.path.normpath之后是否跳出 base。但偷懒的实现直接做字符串检查if .. in path: raise ValueError(path traversal detected).. in path会匹配任何包含连续两点的字符串包括report..final.md。真正该防的是..作为路径段被/包围或位于段首而不是..作为子串。合法文件名里..完全可能出现Unix 允许文件名包含几乎任何字符除了/和 NUL。所以含..即拒绝是错误的启发式。三、根因根因是把子串包含当成路径段穿越子串匹配误判.. in path命中所有连续两点不论其是否构成路径段。未做路径归一化再判段正确做法是用os.path.normpath/PurePosixPath解析再检查每个段是否等于..或解析后是否仍在 base 内。混淆文件名里的..与目录里的..前者是普通字符后者才是穿越。本质用字符串启发式替代了正确的路径语义解析把合法的命名字符当成了攻击特征。四、最小可运行复现下面缩略逻辑复现误拒def bad_safe(path): if .. in path: # 错误子串匹配 raise ValueError(path traversal detected) return path for p in [report..final.md, ../etc/passwd, a..b.txt]: try: print(p, -, bad_safe(p)) except ValueError as e: print(p, - REJECTED:, e) # report..final.md - REJECTED (合法却被拒) # ../etc/passwd - REJECTED (正确拒绝) # a..b.txt - REJECTED (合法却被拒)修复用路径归一化只在段等于 .. 且导致越界时拒绝。from pathlib import Path def good_safe(path, base): resolved (base / path).resolve() base_resolved Path(base).resolve() if base_resolved not in resolved.parents and resolved ! base_resolved: raise ValueError(path escapes base) return resolved五、解决方案第一层最小直接修复最小修法放弃子串检查改为路径解析后判断是否仍在 base 之内..只有当它真的导致跳出 base 时才拒绝文件名里的..不受影响。from pathlib import Path def is_safe_under(path: str, base: str) - bool: base_r Path(base).resolve() target (base_r / path).resolve() return base_r in target.parents or target base_r def search_file(path, base): if not is_safe_under(path, base): raise ValueError(path escapes base directory) # 继续搜索 ...这一层让report..final.md正常通过../etc/passwd正确拒绝。六、解决方案第二层结构化改进把路径穿越判定规则固化成策略对象作为单一事实来源明确按段解析而非子串。from dataclasses import dataclass from pathlib import Path from typing import List dataclass(frozenTrue) class LangChainFilesystemSearchPolicy: 文件系统搜索路径安全策略的单一事实来源。 forbid_substring_double_dot: bool False # 必须为 False否则误拒 resolve_and_contain: bool True allow_dotfiles: bool True def is_safe(self, path: str, base: str) - bool: if self.forbid_substring_double_dot: raise AssertionError(substring .. check causes false rejects) base_r Path(base).resolve() target (base_r / path).resolve() return self.resolve_and_contain and ( base_r in target.parents or target base_r ) def validate(self) - None: if self.forbid_substring_double_dot: raise AssertionError(must use segment-based check, not substring)搜索工具用policy.is_safe安全性由解析后是否越界决定而非文件名长什么样。七、解决方案第三层断言 / CI 守护用 pytest 锁死正确判定import pytest from pathlib import Path from policy import LangChainFilesystemSearchPolicy as P def test_legal_double_dot_allowed(tmp_path): p P() (tmp_path / report..final.md).write_text(x) assert p.is_safe(report..final.md, str(tmp_path)) is True def test_traversal_rejected(tmp_path): p P() assert p.is_safe(../etc/passwd, str(tmp_path)) is False def test_no_substring_check(): with pytest.raises(AssertionError): P(forbid_substring_double_dotTrue).validate() def test_dotfile_allowed(tmp_path): p P() (tmp_path / ..hidden).write_text(x) assert p.is_safe(..hidden, str(tmp_path)) is TrueCI 加一条FileSystem搜索单测必须覆盖文件名含..的合法用例断言不被拒并覆盖真实穿越用例断言被拒。八、排查清单搜report..final.md被拒→ 搜索用了.. in path子串检查误判。文件名里的..是否合法→ Unix 文件名可含..非穿越。是否做了路径归一化→ 用Path.resolve()再判断是否越界 base。真穿越../是否被拒→ 归一化后段为..且越界应拒。CI 是否禁止子串检查→ 扫描.. in路径校验。隐藏文件..x是否放行→ 应放行合法命名。九、小结文件系统文件搜索把路径里出现..子串一律拒绝误伤了文件名中合法含..的情况如report..final.md、隐藏文件..hidden过度防御变成功能缺陷。根因是用字符串子串匹配替代了正确的路径语义解析。第一层改为路径归一化后判断是否越界 base第二层用LangChainFilesystemSearchPolicy把判定规则固化成单一事实来源并禁止子串检查第三层用 pytest 守护合法..文件名被放行、真实穿越被拒。路径安全的通用原则按解析后的路径段判断是否越界而非按文件名长相做字符串启发式。

相关新闻

最新新闻

06-Kalman隔帧轨迹预测

06-Kalman隔帧轨迹预测

Kalman 滤波与隔帧检测:轨迹如何在「无测量帧」上继续走 本文只讲一件事:当检测隔几帧才跑一次时,中间帧没有新的人体框测量,跟踪仍能给出连续轨迹,靠的是 Kalman 预测;有测量时再做 更新。 读完后应能独立…

2026/8/18 12:37:57
【学术福利 | 免费下载 | 硬核干货 | 科研必备】国际学术会议海报模板大礼包:200+高颜排版直接套用,学术会议专用海报模板,免费学术Poster海报模板,科研成果一眼出圈,科研人展示成果的快车道

【学术福利 | 免费下载 | 硬核干货 | 科研必备】国际学术会议海报模板大礼包:200+高颜排版直接套用,学术会议专用海报模板,免费学术Poster海报模板,科研成果一眼出圈,科研人展示成果的快车道

又到学术会议、答辩汇报、成果展览高峰期! 相信很多科研人都有同款困扰:论文做得很完美,却被海报排版拖了后腿。 熬夜几小时手动排版,版面杂乱、重点模糊、配色廉价、层级混乱;不懂学术规范,做出来的海报…

2026/8/18 12:37:57
理解python进程

理解python进程

进程 - CPU密集型王者 概述 操作系统资源分配的基本单位(注意这里的 资源分配 只是分配资源)硬件多核前提下,Python multiprocessing 多进程可以实现真正并行;单进程只能并发,无法并行python的多进程会 真正启动底层的…

2026/8/18 12:37:57
Mem Reduct 完整使用手册:10 分钟驯服 Windows 的内存卡顿

Mem Reduct 完整使用手册:10 分钟驯服 Windows 的内存卡顿

Mem Reduct 完整使用手册:10 分钟驯服 Windows 的内存卡顿 【免费下载链接】memreduct Lightweight real-time memory management application to monitor and clean system memory on your computer. 项目地址: https://gitcode.com/gh_mirrors/me/memreduct …

2026/8/18 12:37:57
微信网页版登录被限制?这款免费浏览器插件三步就能恢复

微信网页版登录被限制?这款免费浏览器插件三步就能恢复

微信网页版登录被限制?这款免费浏览器插件三步就能恢复 【免费下载链接】wechat-need-web 让微信网页版可用 / Allow the use of WeChat via webpage access 项目地址: https://gitcode.com/gh_mirrors/we/wechat-need-web 周一早上九点,你刚在工…

2026/8/18 12:37:57
RAG系统全链路调优实战:从混合检索、重排序到提示工程

RAG系统全链路调优实战:从混合检索、重排序到提示工程

你是不是也遇到过这样的问题:用大模型搭建知识库,结果回答要么是“根据已有知识”,要么就是一本正经地胡说八道?或者,检索出来的文档明明相关,但大模型就是抓不住重点,生成的内容总是差那么点意…

2026/8/18 12:32:57