claude-obsidian 恶意文件归档防御的六道拦截一次看懂【免费下载链接】claude-obsidianSelf-organizing AI second brain for Obsidian Claude Code. Drop any source and Claude reads, links, and files it into one connected knowledge graph of plain Markdown you own. AI note-taking, personal knowledge management (PKM), and an open-source Notion alternative. Based on Karpathys LLM Wiki pattern.项目地址: https://gitcode.com/GitHub_Trending/cl/claude-obsidianclaude-obsidian 是一款开源 AI 第二大脑工具把任意资料丢进知识库收件箱它负责读取、建立链接并归档成 Markdown 笔记。它的归档流水线capture直接接收外部文件因此项目把这条入口当作最大攻击面在 capture.py 与 transaction.py 里写进了一套确定性校验。本文按数据流向讲清每道拦截防的风险、实现位置以及失败时用户会看到的错误码。 收件箱为什么是知识库的第一道防线claude-obsidian 的理念是文件属于你自己知识库就是普通 Markdown 目录capture 文件从inbox/复制进.raw/captured/只读仓库再被加工成带出处的笔记。问题在于inbox/里的任意文件未必干净——文件名可能藏控制字符目录可能被换成符号链接文件还可能在你归档到一半时被替换。SECURITY.md 把这些写成了防御性不变量不是可选增强而是代码在任何时候都必须成立的规则。整套防御沿数据流排布先审路径与文件名再给内容做指纹落盘事务日志兜底中断预算与锁限制资源消耗。 文件进库前会检查哪几类危险路径最直接的风险一个看起来像inbox/notes.md的路径解析后可能落在知识库外面。项目对此做先纸面、再实物的两段检查。纸面检查只看字符串capture.py 的 _validate_relative_directory 拒绝绝对路径、反斜杠和..段并要求路径已预先规范化事务层的 _normalize_vault_path 更严格额外拒绝控制字符、要求 NFC Unicode 归一化并把路径长度限制在 1024 字节。失败时抛出INVALID_CONFIG_PATH或INVALID_WRITE_PATH归档直接中止。纸面合法还不够a/b.md里的a可能是指向别处的符号链接。于是 paths.py 的 assert_within 把符号链接解析掉确认最终位置仍在库内否则抛出PATH_OUTSIDE_VAULT。capture 侧扫描inbox/时_allowed_source_path 会逐段检查中间目录只要途中某级目录被替换成别名即便文件本身没问题也会以SOURCE_SYMLINK拒绝收件箱根目录本身是符号链接则直接报SOURCE_ROOT_SYMLINK。文件名的隐形坑也在同一处拦截。_validate_filename 拒绝控制字符与零宽字符、首尾空格、以点或空格结尾的名字、CON与NUL等 Windows 保留名错误码统一为UNSAFE_FILENAME。再往深处看在不区分大小写的文件系统上Note.md与NOTE.MD是同一个文件事务层的 _assert_no_existing_portable_alias 会枚举同目录兄弟项发现 NFC 加小写折叠后冲突的名字就抛出CASEFOLD_PATH_ALIAS——这类歧义无法留给用户自行分辨只能从写入侧直接禁掉。 内容寻址之后原始仓库为什么改不动文件过了路径关就被复制进.raw/captured/命名方式是内容寻址——拿文件内容的 SHA-256 摘要当文件名形如摘要.md。这个设计把是不是同一个文件变成了可以用一个数字验证的问题。计算指纹时source_identity 会记录读取前后的 inode、大小与修改时间两者不一致就抛SOURCE_CHANGED文件在归档过程中被换过整个操作作废你归档的只能是你看到的那份内容。重复归档同一摘要时_find_existing_capture 会把旧副本逐字节重新校验名字对得上、内容对不上说明仓库被外部改写过抛出IMMUTABLE_SOURCE_CONFLICT。原始区因此是只创建、永不修改同一个摘要只允许对应一份字节。 崩溃之后未完成的写入如何回滚写入崩溃比恶意文件更常见。transaction.py 的 apply_bundle 对每批写入采用预检 日志 原子替换先为每个目标记录预期状态备份留在.vault-meta/transactions/日志目录里后续任一步失败就按 _restore_journal 回滚——回滚每一步都会再验证目标文件没被第三方换过否则抛ROLLBACK_TARGET_CHANGED。断电或进程被杀后recover_incomplete 可以从日志接着恢复而不是让用户面对一个写了一半的知识库。所有写路径还要过一次 _safe_vault_path任何一段路径变成符号链接或 Windows junction 都会抛SYMLINK_WRITE_PATH。 归档数量、体积与并发访问的硬上限合法文件也可能成为炸弹一次塞进数百 GB或用海量小文件拖垮磁盘。CaptureBudget 在进入任何 IO 之前设三道硬限——单批最多 100 个文件、单文件不超过 64 MB、整批不超过 256 MB——超限抛FILE_BUDGET_EXCEEDED或TOTAL_BUDGET_EXCEEDED。捕获队列文档本身限制在 8 MB、4096 条防止一份超大 JSON 耗尽解析预算。并发交给目录锁。CaptureQueueLock 原子创建锁目录持有者把随机 token 写进 owner.json释放前回读验证token 对不上就抛QUEUE_LOCK_OWNERSHIP_LOST锁不会被人顺走。死锁恢复也保守只有确认持有进程已死且锁超龄才清理清理动作本身还要复查锁身份未变。 外部 URL 归档如何防止内网探测网络适配器默认被锁死。validate_https_url 只接受 HTTPSlocalhost、169.254.*、.internal等私网地址以URL_PRIVATE_HOST直接拒绝重定向到白名单之外的域名同样不允许。外部动作只生成惰性计划——一份尚未执行的方案用户明确批准前什么都不会发出。机制速查风险点拦截位置失败行为路径逃逸出知识库assert_withinPATH_OUTSIDE_VAULT操作中止收件箱内出现符号链接_allowed_source_pathSOURCE_SYMLINK/SOURCE_ROOT_SYMLINK文件名含隐藏字符或保留名_validate_filenameUNSAFE_FILENAME大小写别名冲突_assert_no_existing_portable_aliasCASEFOLD_PATH_ALIAS指纹计算中文件被替换source_identitySOURCE_CHANGED原始仓库名字与内容不符_find_existing_captureIMMUTABLE_SOURCE_CONFLICT回滚时目标已被改动_restore_journalROLLBACK_TARGET_CHANGED归档批超预算CaptureBudgetFILE_BUDGET_EXCEEDED/TOTAL_BUDGET_EXCEEDED队列锁被并发窃取CaptureQueueLockQUEUE_LOCK_OWNERSHIP_LOSTURL 指向内网地址validate_https_urlURL_PRIVATE_HOST关键文件速查文件职责claude_obsidian/capture.py归档主流程源文件准入、内容指纹、队列与锁claude_obsidian/transaction.py路径安全与原子写入、日志备份、回滚恢复claude_obsidian/paths.py知识库根识别与路径包含性检查SECURITY.md安全边界声明与防御性不变量清单对用户而言这套机制兑现的保障只有一句你丢进inbox/的文件要么完整归档要么什么都没写不存在中间状态。原始仓库里的字节无法被悄悄替换中断的操作能从日志接上。对一个文件属于你自己的开源知识库来说信任的关键不是把数据锁在某处而是保证入口进来的东西不会被污染。【免费下载链接】claude-obsidianSelf-organizing AI second brain for Obsidian Claude Code. Drop any source and Claude reads, links, and files it into one connected knowledge graph of plain Markdown you own. AI note-taking, personal knowledge management (PKM), and an open-source Notion alternative. Based on Karpathys LLM Wiki pattern.项目地址: https://gitcode.com/GitHub_Trending/cl/claude-obsidian创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考