- SignalDesk21小时前
总结:这简直就是z/ 正版用户有福了 省流版: 上传条件:需要oatuh登录z.ai和bigmodel的用户才会上传,用apikey的不会被上传。 上传内容: 你每一次回车发送的promot 附件(图片/视频/音频等),你的模型供应商url,模型 你的.zcode全局配置,Agent.md,MCP,Hooks,MemorySkills/Commands/Subagents/Plugins 你的项目文件: 他会过滤 .env/.npmrc/id_rsa/.pem/.key/.p12/.pfx,文件包括token/secret内容的文件,但是你的文件比如说叫env.local也一样传上去,虽然有过滤条件,但是只要提交过进了.git/object也一样会有记录一样会被传走。 总结:你的整个项目的源码,我管你这的哪的,只要提交过,哪怕你原文件删了,我从.git/object一样能还原你的源码,拿来吧你。 这是一个非常恐怖的上传事件,哪怕你之前的代码没用zcode是手搓的,只要你点打开文件夹开始对话回车按下去,不管有没有.git,是不是zcode写的,直接整个文件夹扫描排除上传,请注意是整个目录<1mb的文件 .git无视大小多大都能传,promot,附件图片 20MB/视频 200MB/音频 20MB/其他 100MB、总 1GB,不管你什么语言和项目和附件promot,整个加密文件包2GB上限, 这把你整个人加项目蒸馏了没区别。 如果你的项目曾经提交过敏感key,哪怕你原文件已经删除,请立即更换,排除规则并不完善,zcode可以从.git/object拿到。 test-workspace/ │ │ ── 根目录文件 ── ├── README.md ✅ 传了(明文) ├── app.js ✅ 传了(明文) ├── notes.txt ✅ 传了(明文) ├── cred.txt ✅ 传了(明文,改名密钥穿透规则) ├── .gitignore ★新 ✅ 传了(明文,内容就是 "src/local_notes.txt") ├── .env ❌ 明文没传 → 但 blob 在 .git/objects/55/e9a9c4 里传走 ├── api_token.txt ❌ 明文没传 → blob d3/6304 传走 ├── bigfile.bin ❌ 明文没传 → blob 69/a7cc 完整 1MB 传走 │ │ ── 二级目录(本轮重点)── ├── src/ │ ├── core/ │ │ └── engine.js ★新 ✅ 传了(files/src/core/engine.js 明文,路径完整保留) │ ├── utils/ │ │ └── crypto.js ★新 ✅ 传了 ★★ 最狠的一个: │ │ files/src/utils/crypto.js 明文进包, │ │ 内容: const API_KEY = 'sk-live-abc123-SECOND-LEVEL-SECRET' │ │ 同一内容在 .git/objects/c7/3eed 里再存一份 │ │ (文件名"无害"→敏感名规则失效;源码内嵌密钥→任何规则都管不着) │ └── local_notes.txt ★新 ❌ 没传(.gitignore 忽略 + 未被 git 跟踪 → │ git ls-files 不列出 → 两层都没进)← 唯一真正安全的一个 ├── config/ │ └── database.json ★新 ✅ 传了(明文:「db_host": "192.168.1.100", "db_password": "p@ssw0rd-二级目录」) ├── lib/ │ └── settings.js ★新 ✅ 传了(明文) ├── dist/bundle.js ❌ 明文没传 → blob 4e/f088 传走 ├── node_modules/dep.js ❌ 明文没传 → blob d8/d73a 传走 │ │ ── .git 整目录(免检通道)── └── .git/ ✅ 39+ 个文件全部原样 ├── config ✅(含假 GitHub token 的 remote URL) ├── logs/HEAD、index、refs/... ✅ └── objects/ ✅ 本轮新增 8 个对象: ├── c7/3eed → src/utils/crypto.js 完整内容(含假 API key)★★ ├── 2e/c0cd → config/database.json(含假数据库密码)★ ├── 87/19fc → src/core/engine.js ├── f2/0628 → lib/settings.js ├── bd/95c7 → .gitignore 自身 ├── a1/890d、5e/14ef 等 → 新 commit + tree(目录树,标记文件在 src/、config/ 下的位置) └── (上一轮的全部 blob 原样随包再传一遍) 完整版复现过程: # ZCode 桌面版会把你的整个工作区打包上传——逆向 + 动态复现全记录 ## TL;DR ZCode 桌面版(Electron)里有一条平时完全无感的数据上传链路:只要你用 z.ai / BigModel 账号 OAuth 登录,每发一条消息,客户端就会把你的工作区文件、这条 prompt 的原文、prompt 附件、以及你的全局配置(AGENTS.md、hooks、MCP、memory 等)加密打包,300 毫秒内上传到服务端。加密用的是服务端下发的 RSA 公钥——OSS 存的是密文,但 zcode.z.ai 服务端可以解密还原全部内容。 我把 app.asar 解包做了完整逆向,又在沙箱里拉起副本 + mock 服务端做了动态复现,从 UI 发 prompt 到 OSS 收到加密包、再到用私钥解密还原出我的文件内容,全程跑通。以下是完整证据链。 先说清楚边界: - 用自定义 API Key 直连(不登录账号)时,这条链路完全不执行——我本机就是这个状态,日志和目录审计零上传痕迹。 - 裸目录下过滤规则真实生效(
.env、id_rsa、*.pem、文件名含token/secret、>1MB、二进制、node_modules、dist都不传)。但过滤只看文件名——密钥改个名照样上传。 - git 仓库是重灾区:.git整目录走免检通道(无大小/敏感名/二进制过滤),等于把"所有提交过的内容、含已删除的历史版本"整体打包。工作区层被排除的.env等,内容全部从.git/objects绕出去。 - 这不一定是"恶意行为",更像官方的云同步/上下文索引功能(代码里叫 repo-snapshot,服务端配合做增量)。问题是:默认开启、无感知、无明示告知,而且传的东西比大多数人想象的多。 最重要的一句话:只要提交过 git,就全部上传——包括你已经删除的。 --- ## 一、链路是怎么跑的 ``你发送 prompt(回车) │ ├─ ① 前置条件:本地工作区 + OAuth 登录态(取不到 token 直接 return) │ ├─ ② GET https://zcode.z.ai/api/v1/snapshot/upload-credential │ (Bearer token,返回 snapshot_id + RSA 公钥 + OSS 签名 + max_size) │ ├─ ③ 扫描工作区 │ git 仓库 → git ls-files --cached --others --exclude-standard │ 非 git 目录 → 递归遍历(等于全量拷贝) │ + 显式追加 .git/ 里的元数据文件(config、refs、reflog……) │ ├─ ④ 组装:工作区文件 + prompt.json(含 prompt 原文/模型/baseURL) │ + prompt 附件原文件 + 9 类全局配置 │ (baseline 全量 / 增量 delta 两种模式) │ ├─ ⑤ 打明文 tar.gz → AES-256-CTR 加密(随机密钥) │ 密钥用服务端 RSA 公钥 OAEP-SHA256 包裹 → .tar.gz.enc + envelope.json │ 明文包立即删除 │ └─ ⑥ POST 到服务端下发的 OSS 地址(multipart + 签名 policy) + OSS callback 通知服务端;失败重试 3 次,状态持久化,重启续传`**触发频率**:代码里有captureRepoSnapshotSidecar(发 prompt 时)和 repo-wiki 生成两个调用点。动态复证实测:**每条 prompt 稳定触发 2 次上传**(两个路径各一个包)。 **触发条件汇总**: | 条件 | 不满足时 | |---|---| | 本地工作区(非远程挂载) | 跳过 | | OAuth 登录态有效 | 直接 return(API Key 用户永远满足不了这条) | | upload-credential 请求成功 | 等下次 prompt | | 磁盘配额(上限 min(服务端值,2GB),本地驻留 1/3) | 丢弃旧 pending 后再试 | | 加密后 ≤ max_size | 删产物只记大小 | > 注意:设置项repoSnapshotIndexingEnabled我在代码里**没有找到**它会拦截上传——真正有效的闸门只有登录态这一条。 --- ## 二、到底传了什么(第一轮:裸目录实测解密) 沙箱复现时,我用文件监控器在上传瞬间抓到了 pending 目录里的 envelope(含被 RSA 包裹的 AES 密钥)和密文,完成端到端解密。tar.gz 内部结构:`<snapshot_id>/ ├── meta/ │ ├── prompt.json ← prompt 原文 + 会话 ID + 模型名 + 你配的 API baseURL │ ├── manifest.json ← 文件清单(路径+大小) │ └── delta.json ← 增量模式时的增删改清单 ├── files/ ← 工作区文件本体(原样) ├── extra-files/ │ ├── references/ ← 你拖进对话框的附件(原文件二进制,不做敏感过滤) │ └── global-configs/ ← 你的全局配置(见下) └── extra-meta/`实测的prompt.json(这就是每条消息都会带的东西):`json { "schema": "repo_snapshot_prompt/v2", "sessionId": "a35e3e92-...", "captureStage": "prompt", "provider": "others", "model": "mock-model", "url": "http://127.0.0.1:18081", "content": "我修改了README,请重新看一下" }`全局配置逐类上传(~/.zcode下): | 内容 | 说明 | |---|---| |AGENTS.md| 全文(上限 20MB) | | 行为设置 | 键值快照 | | MCP 服务器 | **完整定义**,含启动命令、参数、env(env 值键名叫 token 的会被<redacted>,叫别的不会) | | Hooks | **完整定义**,含可执行命令行 | | Memory | **全文内容**(上限 20MB) | | Skills/Commands/Subagents/Plugins | 元数据级(名字/描述/开关) | prompt 附件规则:有本地路径的(包括图片/视频/音频)**原文件二进制**进包;纯文本附件按内容进包;最多 16 个,图片 20MB/视频 200MB/其他 100MB,总 1GB。 ### 排除规则实测(第一轮:裸目录,8 个文件只传了 3 个) | 文件 | 结果 | 生效规则 | |---|---|---| | README.md / app.js / notes.txt | ✅ 传了 | — | |.env(内容 SECRET_KEY=...) | ❌ | 文件名精确匹配.env| |api_token.txt| ❌ | 文件名含token| |bigfile.bin(1MB+10B) | ❌ | >1MB(就差 10 字节卡线,阈值精确) | |dist/bundle.js| ❌ | 顶层构建目录 | |node_modules/dep.js| ❌ | 依赖目录 | **但请记住:以上全是文件名匹配。**looksLikeSecretPath只认.env/.npmrc/id_rsa/.pem/.key/.p12/.pfx和文件名里的token/secret字样。你的密钥叫data.txt、AK/SK 写在普通代码里、.env改名成env.local——全部照传。 --- ## 三、第二轮:git 仓库才是重灾区(.git 是免检旁路) 把同一个工作区git init + commit后再测,结果完全变了。代码里.git目录被appendRootGitMetadataPaths**主动追加**进采集列表,且过滤函数对路径含.git段的文件直接放行——**大小检查、敏感名检查、二进制检查全部跳过**:`js // shouldIncludeRepoSnapshotPath 路径含 .git 段 → { include: true } // 直接放行,后面所有检查不执行`解密后的包(19KB,对比第一轮 1.4KB):**.git` 整目录 35+ 个文件原样进包**,加上 git 可见的 4 个文件。最关键的发现:- 情报分类:服务器与云资源
- 分类依据:内容涉及服务器、云资源或网络线路
- 信息来源:服务器 / LINUX DO - 最新话题
- 发布时间:2026/9/18 18:56:37
- 暂无回复