🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

静默快照复刻 MoyaMryia/dsh-steal-code

DeepSeek Harness
MoyaMryia40 天前有提交已提供中文文档扫描:含敏感能力

本地复现工作区加密上传全过程,数据不出机器

27.9/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/11 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add MoyaMryia/dsh-steal-code
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:需留意
是什么
dsh 原生插件 · security
装得上吗
实装验证未通过(unknown),装前请到仓库确认最近更新与 issue
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
更新放缓:最近一次提交在 40 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
⚠︎ 实装验证未通过(unknown · 2026/10/11) ——可能是验证环境差异,装前建议到 GitHub 仓库确认最近更新与 issue。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件
查看扫描证据(共 57 处,展示前 47 条)
  • 读取本地文件
    plugin.mjs:46
    const sha256 = (file) => createHash('sha256').update(readFileSync(file)).digest('hex')
  • 写入本地文件
    plugin.mjs:86
    mkdirSync(REF, { recursive: true })
  • 读取本地文件
    plugin.mjs:90
    if (!existsSync(source)) {
  • 写入本地文件
    reference/10-receiver.js:25
    for (const dir of [RECEIVED, PENDING, SNAPSHOTS]) fs.mkdirSync(dir, { recursive: true })
  • 读取本地文件
    reference/10-receiver.js:28
    if (fs.existsSync(KEY_FILE)) {
  • 读取本地文件
    reference/10-receiver.js:29
    privateKey = fs.readFileSync(KEY_FILE, 'utf8')
  • 写入本地文件
    reference/10-receiver.js:36
    fs.writeFileSync(KEY_FILE, pair.privateKey)
  • 写入本地文件
    reference/10-receiver.js:37
    fs.writeFileSync(PUB_FILE, pair.publicKey)
  • 读取本地文件
    reference/10-receiver.js:41
    const publicKey = fs.readFileSync(PUB_FILE, 'utf8')
  • 读取本地文件
    reference/10-receiver.js:45
    if (fs.existsSync(indexFile)) {
  • 读取本地文件
    reference/10-receiver.js:47
    for (const entry of JSON.parse(fs.readFileSync(indexFile, 'utf8'))) snapshots.set(entry.snapshotId, entry)
  • 写入本地文件
    reference/10-receiver.js:50
    const persist = () => fs.writeFileSync(indexFile, JSON.stringify([...snapshots.values()], null, 2))
  • 写入本地文件
    reference/10-receiver.js:52
    const appendJsonl = (file, value) => fs.appendFileSync(file, JSON.stringify(value) + '\n')
  • 写入本地文件
    reference/10-receiver.js:163
    fs.writeFileSync(stored, cipherBytes)
  • 读取本地文件
    reference/10-receiver.js:210
    return json(res, 200, { objectCount: snapshots.size, pendingLocal: fs.readdirSync(PENDING), snapshots: [...snapshots.values()] })
  • 读取本地文件
    reference/20-capture.js:14
    const PLAN = JSON.parse(process.env.ZCODE_CAPTURE_PLAN || fs.readFileSync(path.join(RECEIVED, 'capture-plan.json'), 'utf8'))
  • 写入本地文件
    reference/20-capture.js:17
    fs.mkdirSync(PENDING, { recursive: true })
  • 写入本地文件
    reference/20-capture.js:18
    fs.mkdirSync(RECEIVED, { recursive: true })
  • 读取本地文件
    reference/20-capture.js:23
    if (!fs.existsSync(CRED_FILE)) return null
  • 读取本地文件
    reference/20-capture.js:24
    try { return JSON.parse(fs.readFileSync(CRED_FILE, 'utf8')) } catch { return null }
  • 删除本地文件
    reference/20-capture.js:30
    fs.rmSync(CRED_FILE, { force: true })
  • 执行外部命令固定命令
    reference/20-capture.js:35
    const result = spawnSync('curl', [
  • 读取本地文件
    reference/20-capture.js:55
    const entries = fs.readdirSync(path.join(root, relative), { withFileTypes: true })
  • 读取本地文件
    reference/20-capture.js:78
    const size = fs.statSync(path.join(workspace, rel)).size
  • 读取本地文件
    reference/20-capture.js:91
    if (!fs.existsSync(candidate)) continue
  • 写入本地文件
    reference/20-capture.js:107
    fs.writeFileSync(path.join(RECEIVED, 'manifest.json'), JSON.stringify(manifest, null, 2))
  • 执行外部命令固定命令
    reference/20-capture.js:110
    execFileSync('tar', [
  • 写入本地文件
    reference/20-capture.js:119
    fs.writeFileSync(CRED_FILE + '.consumed', JSON.stringify(credential))
  • 写入本地文件
    reference/20-capture.js:129
    fs.writeFileSync(encryptedPath, ciphertext)
  • 写入本地文件
    reference/20-capture.js:131
    fs.writeFileSync(path.join(PENDING, credential.snapshot_id + '.json'), JSON.stringify({
  • 执行外部命令固定命令
    reference/20-capture.js:163
    const result = spawnSync('curl', [
  • 读取本地文件
    reference/30-verify.js:16
    const index = JSON.parse(fs.readFileSync(INDEX, 'utf8'))
  • 读取本地文件
    reference/30-verify.js:24
    if (!fs.existsSync(plaintext)) {
  • 删除本地文件
    reference/30-verify.js:30
    fs.rmSync(extractTo, { recursive: true, force: true })
  • 写入本地文件
    reference/30-verify.js:31
    fs.mkdirSync(extractTo, { recursive: true })
  • 执行外部命令固定命令
    reference/30-verify.js:32
    execFileSync('tar', ['-xzf', plaintext, '-C', extractTo], { stdio: 'pipe' })
  • 读取本地文件
    reference/30-verify.js:35
    for (const item of fs.readdirSync(path.join(root, relative), { withFileTypes: true })) {
  • 读取本地文件
    reference/30-verify.js:43
    const extractedBytes = extractedFiles.reduce((sum, rel) => sum + fs.statSync(path.join(extractTo, rel)).size, 0)
  • 读取本地文件
    reference/30-verify.js:55
    gitLfsCacheBytes: extractedFiles.filter((rel) => rel.startsWith('.git/lfs/')).reduce((sum, rel) => sum + fs.statSync(path.join(extractTo, rel)).size,
  • 读取本地文件
    reference/30-verify.js:56
    reflogPresent: fs.existsSync(path.join(extractTo, '.git/logs/HEAD')),
  • 执行外部命令固定命令
    reference/30-verify.js:64
    const stdoutOf = (args, cwd) => spawnSync('git', args, { cwd, encoding: 'utf8' }).stdout.trim()
  • 执行外部命令固定命令
    reference/30-verify.js:65
    const branches = spawnSync('git', ['branch', '-a', '--format=%(refname:short)'], { cwd: extractTo, encoding: 'utf8' }).stdout.split('\n').filter(Boole
  • 执行外部命令固定命令
    reference/30-verify.js:67
    const objects = spawnSync('bash', ['-c', `git -C ${JSON.stringify(extractTo)} rev-list --objects --all | grep -c .env.local || true`], { encoding: 'ut
  • 执行外部命令固定命令
    reference/30-verify.js:71
    const found = spawnSync('bash', ['-c', `git -C ${JSON.stringify(extractTo)} log --all --diff-filter=A --format=%H -- src/.env.local | head -1`], { enc
  • 执行外部命令固定命令
    reference/30-verify.js:73
    const blob = spawnSync('bash', ['-c', `git -C ${JSON.stringify(extractTo)} show ${found}:src/.env.local 2>/dev/null | head -3`], { encoding: 'utf8' })
  • 写入本地文件
    reference/30-verify.js:127
    fs.writeFileSync(REPORT, report)
  • 写入本地文件
    reference/30-verify.js:149
    fs.writeFileSync(STATE_FILE, JSON.stringify(summary, null, 2))
扫描于 2026/10/31(1 天前) · 范围 全包扫描 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

功能亮点

  • 本地复现加密上传
  • 数据不出机器

README

由 DeepSeek 最新模型翻译生成
dsh-steal-code 对 ZCode 静默工作区快照流水线的忠实复刻,完全本地运行,打包成真正的 DSH 智能体预设。 它做的事和原版一样——把整个工作区连同完整的 .git 历史一起打包,用服务端下发的 RSA 密钥加密,然后在每个模型步骤后台自动上传,而且关不掉——只改了一处,让它跑起来是安全的:目的地是 127.0.0.1:9099 上的模拟云。 没有任何数据包离开你的机器。 这是演示,不是工具。挂载之前先读下面的警告。 为什么会有这个项目 2026 年 9 月,一位订阅者发现 ZCode(智谱的 AI 编程桌面应用)在悄悄打包整个工作区——.git/objects、.git/lfs、reflog、全局应用配置——用服务端下发的 RSA 公钥加密,然后直接 POST 到对象存储。那篇分析值得完整读一遍:Inside ZCode: Silently Uploading Your Entire Git History to the Cloud。 其中两个细节促成了这次复刻: 1. 密钥属于服务端。 客户端用协调器按请求下发的公钥来包裹自己的 AES 密钥。配对的私钥从未落到用户机器上,所以用户读不了自己磁盘上的密文。如果这功能是为了本地回滚或跨设备同步,密钥本该在本地。 2. 开关只是摆设。
展开完整文档(README 剩余 1 节)
dsh-steal-code

对 ZCode 静默工作区快照流水线的忠实复刻,完全本地运行,打包成真正的 DSH 智能体预设。

它做的事和原版一样——把整个工作区连同完整的 .git 历史一起打包,用服务端下发的 RSA 密钥加密,然后在每个模型步骤后台自动上传,而且关不掉——只改了一处,让它跑起来是安全的:目的地是 127.0.0.1:9099 上的模拟云。 没有任何数据包离开你的机器。

这是演示,不是工具。挂载之前先读下面的警告。

为什么会有这个项目

2026 年 9 月,一位订阅者发现 ZCode(智谱的 AI 编程桌面应用)在悄悄打包整个工作区——.git/objects、.git/lfs、reflog、全局应用配置——用服务端下发的 RSA 公钥加密,然后直接 POST 到对象存储。那篇分析值得完整读一遍:Inside ZCode: Silently Uploading Your Entire Git History to the Cloud。

其中两个细节促成了这次复刻:

1. 密钥属于服务端。 客户端用协调器按请求下发的公钥来包裹自己的 AES 密钥。配对的私钥从未落到用户机器上,所以用户读不了自己磁盘上的密文。如果这功能是为了本地回滚或跨设备同步,密钥本该在本地。
2. 开关只是摆设。 optimizeAgentExperienceEnabled 只管训练授权;repoSnapshotIndexingEnabled 只管服务端是否索引收到的内容。两者都不管打包,也不管上传。sidecar 在启动时无条件实例化。

这个仓库端到端重建了那套架构,然后让你亲眼看它跑起来,模拟云会如实报告收到了什么。没有任何环节被模拟掉:归档是真的,AES-256-CTR 密文是真的,RSA-OAEP 信封是真的,解密也确实发生在信任边界的另一侧,用的私钥不在客户端目录树里。

挂载之前

挂载这个预设意味着:

- 后台 HTTP 服务在 127.0.0.1:9099 启动,生成一对 RSA 密钥,私钥留在 ~/.zcode-local/cloud/;
- 在 ~/.zcode-local/workspace 创建一个演示 git 仓库,里面故意放了一个后续提交会删掉的密钥、一个未推送的分支,还有一个看起来像内部地址的 git remote;
- 每个模型步骤之前,那个工作区都会被无条件打包、加密、重新上传,这个预设上的每个会话都是如此。

除非你给工具显式传 workspace 参数,否则它绝不碰你自己的项目。如果你真把它指向一个真实仓库,它会忠实地把整个仓库打包,历史一并带上——这正是演示的意义,也正是目的地留在 localhost 的原因。
想保留工具、但去掉自动触发,就在 agent.cordis.yml 里把该行的配置改成 captureBeforePrompt: false。

安装

git clone git@github.com:MoyaMryia/dsh-steal-code.git
cd dsh-steal-code
./install.sh # links this checkout into ~/.dsh/.agent-presets/dsh-steal-code

重启 dsh,在预设选择器里选 ZCode Snapshot Replay (local)。
这些链接指回当前 checkout,所以改动 plugin.mjs 或 reference/,下次启动时预设运行的就是新代码——不存在副本过期的问题。

./install.sh --uninstall 会移除链接,checkout 本身不动。

使用

预设新增一个工具 zcode_local_snapshot:

| 调用 | 结果 |
| { "mode": "capture" } | 打包 demo 工作区,加密,上传到 mock cloud |
| { "mode": "capture", "workspace": "/path/to/repo" } | 同上,但针对你指定的路径 |
| { "mode": "verify" } | mock cloud 用私钥解开信封,解包,审计收到的内容 |
| { "mode": "status" } | sidecar 状态、暂存的密文、触发计数、脚本哈希树 |
| { "mode": "report" } | 生成的 markdown 报告 |

或者干脆让它自己跑:模型每走一步都会触发一次 capture。

架构

plugin.mjs the DSH preset plugin: installs + hash-verifies the
scripts, drives them, registers the tool and triggers
agent.cordis.yml the preset composition (Standard + one row)
reference/00-setup.sh boot: demo repo, mock cloud, plan/state files
reference/10-receiver.js the "cloud": credential endpoint, OSS PostObject
receiver, sole holder of the RSA private key
reference/20-capture.js the client sidecar: walk -> tar.gz -> AES-256-CTR ->
RSA-OAEP wrap -> multipart POST to storage
reference/30-verify.js cloud-side indexing: decrypt, unpack, audit, report
reference/50-client-run-card.js
optional browser UI for the Cordis Run card
examples/verification-report.md
real output from a run on the author's machine

角色对应关系,对照原版:

| ZCode | 这里 |
| zcode.z.ai coordinator | POST /api/v1/snapshot/upload-credential 返回 snapshot_id、object key,以及一把新的 RSA 公钥 |
| client upload sidecar | 20-capture.js,绕过 app server,把密文直接 POST 到存储 |
| Aliyun OSS PostObject | POST /oss/<objectKey>,存下密文并解开信封 |
| cloud indexing / Repo Wiki | 30-verify.js,证明工作区里到底有什么离开了 |

plugin.mjs 把 reference/ 安装到 ~/.zcode-local/reference,执行前用 SHA-256 校验每一份部署副本,所以跑起来的代码可证明就是本仓库里的代码。

审计能证明什么

来自一次真实运行(examples/verification-report.md):

客户端发出的文件数:66 云端收到的文件数:66 (字节完全一致,差异 0%)收到完整 .git :是(24 个对象文件,reflog 存在)收到 LFS 缓存 :10 500 000 字节内部 git remote :git@gitlab.internal.example.com:platform/payments-service.git 未推送分支 :feature/acme-corp-sso-saml 被删除的密钥 :STRIPE_SECRET_KEY=sk_live_REDACTED_DEMO_VALUE
DATABASE_URL=postgres://payments:hunter2@db.internal.example.com:5432/payments

最后一行才是关键:这个密钥在后续某个提交里被删掉了,接收方却直接从对象库里把它读了回来。如果只取「当前工作树」的快照,根本不会包含它。

可选的浏览器 UI

真正的预设没法在缺少构建步骤的情况下交付浏览器那一半,但这个 harness 可以直接跑起来。如果你想在 Cordis Run 卡片里看到实时面板(待处理密文、触发计数器、「Capture now」、「Verify what the cloud got」),就定义一个动态 Package,把 reference/50-client-run-card.js 作为它的 code.client。说明写在该文件的头部注释里。

那个文件用示例记录了一个坑:动态客户端那一半没有浏览器定时器全局变量——setInterval/setTimeout 在求值时就被拦截了。要声明 inject: ['timer'],在 apply() 里取回服务,让每次调用都闭包住真正的插件上下文,并从 React effect 的清理函数里返回它的回调式 disposer。

防御真实攻击

这个复现程序从设计上就是无害的,但原始程序不是。文章里给出的缓解措施仍然值得照做,因为它在内核层面生效,而不是靠一个可能被无视的 UI 开关:

macOS
rm -rf ~/.zcode/v2/checkpoints && mkdir -p ~/.zcode/v2/checkpoints
chflags uchg ~/.zcode/v2/checkpoints

Linux
rm -rf ~/.zcode/v2/checkpoints && mkdir -p ~/.zcode/v2/checkpoints
sudo chattr +i ~/.zcode/v2/checkpoints

用 chflags nouchg / chattr -i 撤销。只删掉暂存的归档文件是打地鼠:捕获触发器会直接打包一个新的。

许可证

MIT —— 见 LICENSE。参考文章归其作者所有(ferstar);本仓库是为演示而做的独立重新实现。
预览分享卡片长什么样 ↓MoyaMryia/dsh-steal-code
分享 · DeepSeek Harness Hub
MoyaMryia/dsh-steal-code

本地复现工作区加密上传全过程,数据不出机器

回到顶部