周六早上九点,我的技术群突然被一张截图刷屏:请求记录里反复出现某个域名,路径参数带着workspace和git两个关键词。发图的人说,他在本地开发机上安装了 ZCode,只是启动了一下 IDE,抓包工具就看到了这些外联请求。截图传到第三个群时,标题已经变成了“ZCode 静默上传 Git 历史”。当晚,我的私信箱里多了三封读者来信,都在问同一件事:这工具还能不能用?我团队的项目是不是早就被上传了?
这应该是近半年里,AI 编程助手领域最典型的一场“信任危机”样本。作为常年和这类工具打交道的开发者,我觉得把整个 48 小时的发酵过程、技术边界和应对方法完整复盘一遍,比单纯跟风卸载更有价值。它涉及的问题不仅仅是“某个工具是否有罪”,而是我们所有人在使用 AI 编程助手时,都要面对的一个核心矛盾:工具需要读取我们的代码才能提供智能建议,但到底读到哪一层算是合理上下文,哪一层算越界采集?
我先把话说在前面:这篇文章不是任何一方的最终结论,所有现象均来自社区公开披露和可复现的抓包证据。我更想做的事,是带着你把排查思路走一遍,让你以后遇到任何疑似“偷偷上传”的工具时,都能自己动手验证,而不是只靠截图判断是非。
时长两天的“危机时间线”有不少值得回味的细节。下面我一段一段拆开讲。
1. 48小时时间线:一次“正常启动”引发的信任崩塌
我在整理整个过程时,发现这场风波最戏剧化的地方在于:最初触发怀疑的,并不是用户主动做了一个什么复杂操作,而只是一个“启动 IDE”的常规动作。这恰恰击中了开发者最敏感的神经——如果连启动都会有数据外联,那工具的自我克制能力就很可疑了。
1.1 第0小时:一张 Wireshark 截图和一个“路径拼接”细节
周六十点前后,有开发者在社区发帖,说他用 Wireshark 监听本地网卡时,看到 ZCode 相关进程在 IDE 启动后不久就发起了外联请求。请求 URL 里出现了一段类似动态拼接的路径,里面带有工作区目录名、仓库名乃至.git目录的引用。
真正让群里讨论升温的,是发帖人补了一张对比图:他换了三个项目窗口,URL 里的路径参数也跟着变化。这说明对方明显在做“按项目维度收集信息”的动作,而不仅仅是发送一个固定的埋点。这个细节很快让很多原本持观望态度的人开始倾向前一种判断——这不是崩溃上报,更像是在收集项目级上下文。
我特意把时间点记下来,是因为在随后 12 小时内,这张截图被反复转录、添加文字说明,甚至出现了多个版本。不同版本的截图上,请求域名和请求体被标注得越来越满,解读也越来越像“实锤”。
1.2 第24小时:从“单点问题”到“群体性复现”
周日中午,事件进入第二阶段。有人按照最初的复现步骤,在自己的测试机上用代理工具抓取请求,发现了同类现象,而且路径结构中除了工作区路径,还出现了.git/index、.git/config之类的名字。到这里,话题从“某个人的网络有问题”转向“可能普遍存在”。
这个阶段的传播速度非常快。至少三个技术社区出现了相关主题帖,视频平台上也有人录了五分钟的“复现全过程”,弹幕里全是“卸载了”“看不懂但大为震惊”。一些程序员开始翻自己本地的日志目录,想确认 ZCode 从安装到现在,到底建立过哪些连接,传输了多大体积的数据。
印象最深的是有个人提出:如果只是读取工作区内文本文件,那问题还停留在“上下文采集”的范畴;但一旦涉及.git目录,性质就完全变了,因为 Git 的对象文件是压缩格式,普通埋点根本没必要读它。
1.3 第48小时:官方回应的出现,以及另一种声音
周一下午,事件进入第三阶段。官方渠道给出了回应,核心大意是:相关请求与调试诊断、数据统计有关,不涉及源代码上传,且部分上报开关可以在配置中关闭。这条回应发布后,社区迅速分成两派:一派认为解释站不住脚,要求公开更详细的技术说明;另一派则认为应激反应过度,很多 AI 编程助手都会收集工作区元数据用于功能优化,只有出现“实际的文件内容上传”才能算实锤。
与此同时,有人提出了一个反向可能性:某些请求是本地代理服务发出的,URL 里带有.git字样,但实际读取的可能只是仓库体积、分支数量这类轻量元数据,并非把.git对象数据打包上传。这在技术上完全说得通,但问题在于,普通用户无法通过 Wireshark 直接看清 HTTPS 解密后的请求体,导致双方都拿不出绝对坚实的证据。
我把这三个阶段拉平看,发现整件事的引爆点,其实是“用户毫无感知”这六个字。
2. 合理的上下文读取与越界的“静默上传”:到底差在哪一步
AI 编程助手这类工具天然需要读取代码,否则补全和问答就是无源之水。但“需要代码”和“需要把代码传出去”是两回事,更准确地说,用户对“传出去多少内容、什么时候传、传给谁”的知情程度,才是判断功能合理性的关键。
2.1 补全、项目问答、崩溃上报这三类合法需求
首先要承认,任何一款 AI 编程助手要想干好活,都有几项绕不开的数据需求:
- 补全:需要当前文件内容、光标前后字符、文件语言类型、项目内模块的引用关系。
- 项目级问答:需要理解整个仓库的文件树、核心目录结构、某个函数跨越多个文件的调用链,这种场景会涉及读取文件内容和摘要。
- 崩溃上报与性能统计:需要 IDE 版本、插件版本、操作系统类型、堆栈异常信息,可能还包括最近几次操作的 API 名称,以便定位问题。
这三类需求在桌面 GUI 流程里通常都有对应的入口:要么是功能面板上一个明确的“分析整个代码库”按钮,要么是弹窗提醒“是否允许发送崩溃报告”。只要提醒够清楚,用户给了授权,就算读取范围再大,也不至于引发伦理争议。
2.2 只要有“仓库根目录”这个字段,边界就开始模糊了
这场风波里的难点在于,很多请求的 URL 路径中,既含有类似workspace的字段,另有类似project和repository拼接的参数。从工程角度说,项目问答确实需要知道仓库根目录的绝对路径,否则没法定位什么文件属于当前项目。
但问题也恰恰出在这里:当你把“仓库根目录路径”作为一个变量传出去,服务端就多了一个进行更深度检索的入口。如果服务端设计了一个“收集工作区上下文”的通用接口,那发送方很容易把.git文件夹也一并划入读取范围,因为从代码层面看,walk(workspace_dir)这种递归遍历,本身就会包含.git。
所以我觉得,舆论咬住“包含.git相关路径”不放,并不是因为开发者不懂技术,而是所有人都在担心一个隐藏编写者:调用仓库遍历接口时,写代码的人有没有做一层“排除敏感目录”的过滤?
2.3 为什么偏偏是.git目录让开发者集体炸毛
就算是不太熟悉 Git 内部原理的新手,也应该知道一个换位思考:.git目录不是一个普通文件夹,它几乎是项目完整生命周期的暗箱。
.git/config中包含远程仓库地址,有时还残留着明文凭证。.git/logs/中包含所有分支的历史操作记录,能推断出项目时间线和人员习惯。.git/objects/中保存着所有历史版本的文件快照,即使后来删除的文件、覆盖掉的配置项、旧版含密码的.env,都能从对象库里挖出来。- 提交作者邮箱、昵称、时间戳,这些元数据同样可以被整理成画像。
Git 的设计哲学是“几乎不删除任何历史”,所以“上传 Git 历史”比“上传当前工作区代码”要严重得多。你可以把前者理解成把同事的手机通讯录、聊天记录和相册回收站一并打包,后者不过是“把你现在正盯着的屏拍给别人看”。这两种风险量级,差着几个数量级。
2.4 真正的雷区是“静默”,而不是“读取”
我再退一步说,即使最终查明,ZCode 在那一轮请求里上传的只是仓库元数据和文件树,不包含文本内容,危机依然会爆发。因为对用户而言,做出任何“自动”操作并且不给出可见提示,就已经破坏了信任前提。
把这个问题换成生活场景你会更容易理解:家里的扫地机器人每天定时清扫,这事你需要知道吗?答案是需要。哪怕它扫完只报告“清扫面积 30 平方米,用时 20 分钟”,如果它没有告诉你“会把家里的户型图存到厂商服务器”,大多数人依然会觉得被冒犯。开发者对代码的领地意识,比对家庭户型图还要强十倍。
所以,无论这件事最终定性如何,“静默”这两个字都已经是产品设计层面最直接的败笔。好的工具不需要做到完全不联网,但至少要让用户打开网络活动面板时,能清楚看到“刚才我读了一个文件树,我正要把它发送到某个服务器用于生成代码建议”。没有这一步,所有的功能理由都特别苍白。
3. 自查程序:用日志、抓包和一颗标记文件,一天内验证流言
事件发酵之后,我做了两件事:第一,没急着卸载 ZCode;第二,给本机搭了一个最小化的审计环境。因为我的原则是,判断一个工具是否越界,不能只看社区截图,必须自己在可控范围内拿到证据。这套排查流程对任何 IDE 插件、AI 编程助手、内网代理工具都适用,我建议你收藏备用。
3.1 先查目录权限与配置文件
第一步不用抓包,而是打开插件或应用的安装目录和配置目录,看看有没有开关能关掉数据上报。以 ZCode 为例,通常在用户主目录下会有.zcode或AppData/Roaming/ZCode这样的配置目录,里面一般放着settings.json或config.json。
重点找几个字段:
telemetry.enabledanalytics.enabledupdate.checkexperimental.reportallowSendUsageData
如果找到这类字段,先全部改成关闭状态,然后重启工具。这一步能直接切断一部分低级别的统计上报。对于没有明确开关的工具,你要做的就是进入第二步,观察它是否仍存在外联行为。
3.2 建一条干净的观察通道
在正式观察之前,我给你一个重要建议:别用公司电脑做这个实验,尤其是那些绑定了公司证书、内网代理的机器。公司网络里本身就存在大量合法的审计流量,你很难区分哪些是 ZCode 的行为。自己在家里找一台测试机,或者开一台虚拟机,效果会干净很多。
工具方面,最简单的组合是:
- Windows:
Wireshark加netstat命令,或者直接用Fiddler开启 HTTPS 解密。 - macOS/Linux:
tcpdump加lsof命令,或者使用mitmproxy做代理观察。
以 Linux 或 macOS 为例,先找出进程 PID:
lsof -nP -iTCP -sTCP:ESTABLISHED | grep -i zcode如果看到连接列表,再针对具体端口抓流量:
sudo tcpdump -i any -s 0 -A host 目标IP地址 and port 443 -w zcode_capture.pcap如果使用 mitmproxy,可以先设置系统代理指向8080端口,再启动:
mitmproxy --listen-port 8080 --set console_eventlog_verbosity=info打开代理后,工具访问的所有域名和 HTTP 路径都会实时滚动在终端里。你不需要立刻做 HTTPS 证书信任,光是看 URL 列表,就能大致判断它连了哪些地址、走了哪些路径。
3.3 三次场景对照,记下三个关键信号
为了让证据更有说服力,我习惯做三次对照实验,而不是只开着工具发呆:
第一次:什么操作都不做,启动 IDE 后静置 10 分钟,记录外联域名和路径。
第二次:打开一个非敏感项目,手动触发几次代码补全和项目问答,记录请求变化。
第三次:打开一个包含大目录、多文件的项目,再触发一次“分析整个代码库”之类的功能,记录请求体大小。
三次记录放在一起对比,重点看三个信号:
- 域名特征:请求是发往官方主域名,还是某个独立的对象存储域名?如果出现对象存储域名,通常意味着可能会有文件上传,而不只是 JSON 请求。
- 路径特征:URL 里有没有
.git、.env、config.py这类敏感文件名?有没有二进制文件后缀? - 体积特征:正常遥测的请求体一般只有几 KB,如果请求体出现几十 KB、几百 KB,那大概率不是简单的用量统计。
你在这一步不用担心抓包数据过于庞大,毕竟我们只观察 20 至 30 分钟的实际操作,远比网上流传的万能截图可靠。
3.4 用“标记文件”拿到最直观的实锤
如果你想拿到更直接的证据,我推荐一个非常有效的技巧:制作一颗“数字跳蚤”。比如在一个测试项目的.git目录下,手动创建一个内容完全独特的文件,名字就叫audit_marker_2025.txt,里面写下一段随机字符串:
这条字符串只存在于我的本地测试仓库,如果它在任何日志或网络请求里出现,说明存在对外传输。然后你正常使用工具,触发项目分析与补全,之后到抓包数据里搜索audit_marker_2025。搜不到,至少能说明工具没有碰这颗标记文件;搜到了,那几乎就是铁证,因为它不可能通过任何合法场景被发送出去。
这个方法的妙处在于,它完全绕开了“机密代码泄露”的对立争论,因为标记文件本身没有任何商业价值,你用它只是为了检验读取和传输行为。如果工具连这种无名测试文件都会外传,那它在真正的生产项目里会做什么,答案不言而喻。
4. 风波之后,我调整了 AI 编程助手的使用“红线”
我身边不少同事在 48 小时内直接卸载了 ZCode,但两个月后,有几个人又悄悄装回来了。原因是:没有 AI 助手写代码的效率,他们接受不了。我理解这种反复,所以我不劝任何人彻底放弃 AI 编程助手,我只建议大家把“信任”这个因素从感受问题变成工程问题。
4.1 开工前先给插件“画像”
在认真使用任何一款新工具前,我会花十分钟整理一份“画像清单”:
- 它是由哪家公司开发的?主运营主体是哪家?
- 它是否支持完全离线模式,或者至少支持关闭联网功能?
- 它提供哪些远程 API 接口?接口域名是否对外公开?
- 它的隐私政策里对“代码样本使用”的描述是“用于改进模型”还是“仅用于请求转发”?
- 安装目录是否有可读的说明文档,允许我关闭数据上报?
这五条清单看起来基础,却能筛掉大量明显不合适的工具。如果你连它的隐私政策都找不到,那就不应该让它在公司源码目录里自由奔跑。最好的做法是:在测试机上安装完,先用抓包工具观察一周,再把它带到正式项目里。
4.2 高敏项目要和外网建立“隔离带”
现在我给团队定的规矩是:涉及预售中的产品、金融、医疗或者高度竞争领域的项目,默认不让 AI 编程助手直接读取全仓库。如果你确实需要补全能力,有以下几种替代方案:
- 专门开一个“脱敏工作副本”,把源码里的业务敏感字段替换成通用变量,再让 AI 助手扫描这个副本。
- 只针对单文件启用补全,不启用“整个代码库问答”这类功能。
- 把 AI 助手配置指向企业私有模型服务,数据不出内网。
- 如果配置里存在“上传文件”的选项,一律禁止,改用剪贴板手动粘贴需要问询的片段。
这个做法的本质,是把 AI 助手当“实习生”而不是“核心成员”来对待。你可以让实习生帮忙查资料、做总结,但不会把公司保险柜钥匙直接塞给他。从工程效率来讲,宁可损失一点补全的上下文完整性,也要保住源代码在发布前不可外泄。
4.3 让工具处在“可审计”状态,而不是“黑盒”
如果你的项目没法完全禁止远程工具,那么至少让它的行为处于“可审计”状态。我的具体操作是:
- 在本机配置防火墙规则,只允许开发工具访问必要的更新域名和请求域名。
- 定期运行网络连接查看命令,确认没有异常进程在向未知 IP 外发数据。
- 每个季度重读一遍插件的 ChangeLog,看它们是否新增了遥测字段或对象存储域名。
- 对团队新增的 AI 工具统一做一次“最小权限评估”,评估者至少包括一名后端工程师和一名安全负责人。
建立一个团队级的检查表远没有想象中复杂:
| 检查项 | 通过标准 |
|---|---|
| 工具是否支持关闭遥测 | 有明确开关,关闭后重启不恢复 |
| 外联域名是否全部可解释 | 每个域名都能对应官方服务或更新服务 |
| 上传内容是否限制在工作区 | 不存在读取.git或家目录文件的行为 |
| 是否有撤离方案 | 卸载后不残留计划任务和守护进程 |
| 是否允许代理环境观察 | 在系统代理下能够正常抓包看到明文请求 |
我见过很多团队明明有安全制度,却在 AI 工具面前全员失灵,原因就是开发者嫌麻烦。可经历了这次 48 小时事件,我想说的是:嫌麻烦的成本,远远低于代码被传出去之后的公关成本和漏洞暴露成本。
5. 48小时后再看三种可能:“误会”、“过度采集”还是“设计缺陷”
如果只停留在“卸载还是保留”的层面,那这次事件就没被讲透。我觉得更有价值的复盘,是承认信息不完整的前提下,把几种可能的真相都想清楚。社区里流传最广的判断有三类,我逐一说说自己的观察。
5.1 可能一:遥测功能被做成了“过宽的桶”
这是最合理也最常见的工程失误。很多工具做埋点采集时会写一个通用collect()函数,把所有工作区信息都塞进一个 JSON 对象里。工程师当时可能只想着“先采集下来,后续再决定用什么”,结果把仓库路径、文件列表、Git 配置摘要全放在同一个请求里。
这种失误的特点是没有恶意,但极不负责任。因为你一旦把数据采到服务器上,服务器就有权限打开文件内容;即使产品规定“只看文件路径”,内部员工误操作或数据库被拖库时,泄露范围是无法收窄的。把“能采到的数据”和“必须采的数据”分开,是隐私设计的底线。
5.2 可能二:第三方插件或 Skill 机制“越权”
ZCode 这类工具现在都支持扩展技能和外部插件,热词里也能看到“zcode添加什么skill好”这类搜索。技能系统给工具带来强大定制能力的同时,也带来新的问题:第三方插件是否继承了主程序的所有权限?
如果某个 Skill 被设计成“需要读取仓库全文来找 Bug”,它一定会调用主进程的工作区遍历接口。这个接口读多少内容、排除哪些目录、是否访问.git对象,取决于插件作者写代码时的边界感。对了,我在这轮排查中看到不少工具的公网仓库结构和 .git 内容被标记为高优路径,这种定义通常来自工具内置的“工程上下文”能力,完全可以做到只看文件树不读对象。
所以,如果你安装了多个技能插件,出问题时的责任归属会变得很复杂。公司可以推给它说“是第三方扩展越权”,但用户只会记住主程序的品牌。
5.3 可能三:误读和夸大,但恐惧是真实的
也不能排除另一种可能:抓包截图里出现了.git相关字样,但实际请求体只是发送了仓库分支数量和最近提交时间,而服务端用这些数据生成解锁某种特性开关。如果是这种场景,社区把“包含关键字”当成了“上传历史文件”,确实存在夸大。
但只要产品没有第一时间给出足够清晰的时序日志和请求体样例,这种夸大就不可能被平息。用户没有义务使用逆向工程去理解产品的善意,产品的责任是主动证明自己的克制。用含糊的“请求用于优化体验”回应用户,只会放大不安。
5.4 透明三原则:我的评估标尺
这轮风波给我留下的有效资产,是一把可以套用到所有 AI 编程助手上的尺子:
- 原则一:可读。 所有被采集的数据,应该在本地日志里以人类可读的形式留痕,而不是存在不透明的缓存文件里。
- 原则二:可见。 每次从工作区读取数据并准备上传前,界面上要有明确的指示,甚至可以在状态栏显示“已读取文件数”和“准备上传字节数”。
- 原则三:可撤回。 用户既可以选择关闭整个联网问答能力,也可以选择仅禁用项目上下文上传,而不是只有一个“完全同意或完全卸载”的二元选项。
这三条原则不仅适用于商业 AI 助手,也适用于团队自研工具。如果连自己的产品都做不到对自己透明,用户凭什么相信它不会偷偷用代码改进模型?
6. 给所有开发者的最后一句话:审计权,比口碑更可靠
这场 48 小时信任危机,表面上是一次产品事故或舆情事故,但本质上暴露的,是整个 AI 编程助手行业在“用户知情权”上的集体滞后。我也清楚,很多人并不在意服务器端到底拿代码做了什么——他们只在意自己有没有说“可以”,以及工具是否尊重了这句话。
现在的现实是,AI 编程助手已经成为生产力的一部分,没有人愿意退回纯手动补全时代。所以我不打算劝说任何人“终远离所有云上代码工具”,我想说的是:每当你决定使用一款新的 AI 工具,第一件事不是看它在媒体上的口碑,而是亲手验证它的网络行为。口碑有滤镜,而抓包数据不会撒谎。
我在实际排查 ZCode 时养成的一个小习惯,现在也分享给你:每次安装完新工具,我会先运行一段十分钟的代理观察,然后保存成截图放进笔记;下次工具更新完再观察一次,对比新旧请求列表。别小看这个步骤,很多工具都是在一两次版本迭代后悄悄加入了新的遥测域名。
一个工具能不能长期留在你的开发环境,不取决于它宣称自己有多强大,而取决于你能不能随时回答这三个问题:它刚才读了什么?它要发给谁?我是否同意了?如果这三个问题里有一个答不上来,你应该像我一样,把它打入冷宫,直到它把话说清楚为止。