发布时间:2026/8/18 9:22:44
【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 守护合法..文件名被放行、真实穿越被拒。路径安全的通用原则按解析后的路径段判断是否越界而非按文件名长相做字符串启发式。

相关新闻

2026/8/18 9:17:43

ClickFix 投递下 AmnesiaStealer 浏览器会话劫持威胁研究

—— 针对 macOS 平台新型窃密恶意软件的实证分析 摘要:macOS 平台长期存在系统安全性被过度高估的认知,攻击者逐步减少对系统底层漏洞的依赖,转而以社会工程手段作为主要入侵入口。AmnesiaStealer 是 2026 年公开披露的基于 Rust 语言开发的…

2026/8/18 9:17:43

手把手本地部署AI角色聊天机器人:基于Ollama与Open WebUI的实践指南

最近在尝试将AI聊天机器人本地化部署时,发现很多教程要么聚焦于动辄数十GB的“庞然大物”,要么就是云端API调用,对于想快速在个人电脑上搭建一个轻量、有趣、可定制化角色聊天机器人的开发者来说,门槛依然不低。特别是想结合特定I…

2026/8/18 11:38:23

XMC1100嵌入式开发:C++面向对象编程实践与性能优化

1. 从C到C:在XMC1100上迈出面向对象的第一步 很多从单片机入门的开发者,对C语言都相当熟悉。寄存器操作、位运算、状态机,这些是嵌入式开发的基石。但当项目规模稍微扩大,比如需要管理多个传感器、复杂的通信协议栈,或…

2026/8/18 11:38:23

嵌入式开发中GPIO.h头文件缺失问题的系统排查与解决指南

1. 从一次深夜调试说起:为什么一个.h文件能让人如此头疼?凌晨两点,屏幕的冷光映在脸上,编译器的报错信息像一堵墙横在眼前:“fatal error: GPIO.h: No such file or directory”。相信每一位从事嵌入式开发的朋友&…

2026/8/17 10:49:52

工业通信系统底层逻辑:04 反射——高频能量撞墙之后会发生什么?

第四篇:反射——高频能量撞墙之后会发生什么? —— 你以为信号已经过去了,其实它正在回来打你 老Q的现场笔记 第五季,我们正式进入工业神经系统层。这里不再是单个设备的战斗,而是整个工厂“经脉”层面的秩序之战。从这一篇开始,你将第一次看清:看似简单的信号传播,背…

2026/8/18 6:58:27

工业传感器与变送器详解:序章 从物理世界到工业数据

序章 从物理世界到工业数据 ——重新认识工业传感器与变送器 工业自动化系统正变得日益复杂。今天的工业现场早已不是简单的控制回路,而是由多层技术共同构成的立体体系:PLC、DCS、SCADA、MES、工业互联网、边缘计算与人工智能。控制系统可以执行复杂算法,工业网络可以实现…

2026/8/18 0:02:05

Qwen3.8-27B本地部署实战:17GB内存运行270亿参数大模型

1. 这篇文章真正要解决的问题 你是否曾对动辄需要上百GB显存才能运行的百亿参数大模型望而却步?是否觉得在个人电脑上部署一个功能强大的语言模型是天方夜谭?最近,通义千问团队发布的 Qwen3.8-27B 模型,宣称仅需 17GB 内存即可在本…

2026/8/18 0:02:05

ME3169 36V,8A,180KHz 恒压Buck DC-DC 转换器

概述ME3169 是一款180KHz,PWM 模式恒压Buck DC-DC 转换器,8V 到36V 宽工作电压范围,低纹波,内置低导通电阻功率MOS。ME3169 内置环路补偿电路,可以减少外围元器件数量。内部设计有恒压环路,可以通过外部电阻…

2026/8/17 15:07:41

实测才敢推 AI论文网站 2026最新测评与推荐

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。一、综…

2026/8/17 17:27:06

2026必备!AI论文网站测评:最新推荐与深度对比

2026年真正好用的AI论文网站,核心看生成的论文质量、低AI味、格式正确、学术适配四大指标。综合实测,千笔AI、ThouPen、豆包、DeepSeek、Grammarly 是当前最值得推荐的梯队,覆盖从免费到付费、从中文到英文、从文科到理工的全场景需求。 一、…

2026/8/18 7:12:40

摆脱论文困扰!盘点2026年全网爆红的的AI论文写作工具

一天写完毕业论文在2026年已不再是天方夜谭。2026年最炸裂、实测能大幅提速的AI论文写作工具,覆盖选题构思、文献整理、内容生成、格式排版等核心场景,真正帮你高效搞定论文难题。 一、全流程王者:一站式搞定论文全链路(一天定稿首…