---
layout: post.njk
source: https://yage.ai/share/coding-agent-setup-install-boundary-20260720.html
speaker: yage.ai
title: Coding Agent 还在配置环境，第三方代码已经运行了
date: '2026-07-20'
summary: 文章探讨了在配置开发环境时，Coding Agent 可能因依赖管理工具（如 package manager）的安装脚本而意外运行第三方代码的风险。核心观点指出，开发者等待环境就绪的时间差可能导致软件包中的安装脚本提前执行，使得项目尚未启动时代码已开始运行。文章还分析了不同类型的潜在攻击路径，包括通过修改文档、利用包名差异或依赖版本漏洞等方式，以及如何通过在安装前对依赖信息进行严格审查来构建安全边界。
area: tech-engineering
category: ai-application
tags:
  - coding-agent
  - package-manager
  - dependency-security
  - setup-process
people: []
companies_orgs: []
products_models: []
media_books: []
draft: true
status: evergreen
---

把一个陌生仓库交给 Coding Agent
后，很多人的第一句话是：“先把项目跑起来。”过去由人配置环境，至少还要读一遍文档、逐条复制命令。Agent
则会读完说明，直接生成并执行安装命令。人也因此很容易把 setup
当成准备工作。

预印本论文 Setup Complete, Now You Are Compromised
指出了这里的时间差：下载依赖本身就可能执行代码。开发者还在等待环境就绪，软件包里的安装脚本或许已经开始运行。等到最终
diff 出现，第一次代码执行可能早已结束。

论文作者围绕这条路径构造了十二个场景、五类攻击，并测试九种由不同模型和客户端组成的
Coding Agent
配置。结果均来自作者实验，目前没有独立复现；这些构造场景也不能证明现实攻击已经普遍发生。实验细节与限制可查阅论文 HTML 版。

## “把项目跑起来”已经包含了一次代码执行

为了启动项目，Agent 会先读 README 和依赖配置，例如
pyproject.toml、requirements.txt，有时还要参考
Makefile 或 CI 配置。接着，它调用 pip、npm 或
Cargo，从外部下载软件包并装进开发环境。下文把这类依赖管理工具统称为
package manager。

获取软件包不只是复制文件。Python 包可以在构建或安装时运行
setup.py，首次导入时还会执行 __init__.py；npm
包可以设置 postinstall；Cargo 构建依赖时会运行
build.rs。这些入口原本服务于编译和环境配置，也让软件包能够在安装、构建或首次导入时执行代码。

如果项目说明把 Agent 引向攻击者控制的软件包，package manager
就可能运行其中的代码。此时 Agent 还没开始修改业务文件，开发者也没有最终
diff 可看。项目尚未启动，不代表第三方代码尚未运行。

恶意代码也不必出现在仓库里。项目配置或 Pull Request
可以只有一项看似普通的依赖变更，真正要运行的代码留在外部软件包中，等
package manager 主动下载。

Coding Agent
从项目说明生成安装命令，package manager
随后执行外部软件包中的安装脚本；检查点必须位于安装开始之前

## Agent
没有收到恶意命令，为什么仍会照做

我在 2026 年 4 月的《AI
编程工具的配置文件，现在是攻击入口》里讨论过另一种风险：攻击者把恶意文字放进仓库，Agent
误把这些文字当成指令。这篇论文里的安装要求却不需要伪装成恶意命令。安装依赖本来就是开发者授权的正常任务。

论文作者做了一组对照。他们让程序在报错信息中建议安装攻击者指定的软件包，九种受测配置全部拒绝了请求。在这组实验里，客户端把程序输出当作不可信内容，没有直接照做。

同一项安装建议写进项目说明，角色就变了。Agent
需要参考这些文档才能配置环境；如果一概拒绝文档里的安装要求，“把项目跑起来”也就无法完成。

攻击者因此可以只修改文档或依赖配置，让安装命令指向另一个软件包或下载地址。审查者看到的是一项依赖变更，不会自动看到那个外部软件包在安装时做了什么。

## 一个正常包名，也可能把代码带到错误的地方

一条安装命令至少决定三件事：安装哪个包、从哪里下载、使用什么版本。论文发现，Agent
对这三项选择的判断并不一样。

明显的错别字最容易引起警觉。作者把 transformers 拼成
tranformers 时，几乎所有受测配置都发现了异常。换成
azurecore 和真实包 azure-core
这样的分隔符差异，结果就取决于具体的模型与客户端组合。同一个模型换一个客户端，实验结果也可能不同。

包名正确，下载来源仍可能改变。package manager 通常从默认的
registry，也就是软件包索引，取回代码。项目使用私有包时，可能通过
--extra-index-url
增加另一个索引；正常包名也可能因此从攻击者控制的来源解析和下载。论文报告，客户端拦截这类场景的次数，整体少于明显错拼包名的场景。

版本是另一条路径。作者保持包名和来源正常，只要求安装已经列入 CVE
公开漏洞目录的旧版本。九种配置都完成了安装，部分配置随后才给出警告。这里没有证据表明攻击者的代码已经运行；结果是开发环境进入已知脆弱状态，为后续利用留下条件。

明显错别字容易触发警告后，风险仍可转向更像真实名称的变体、外部软件包索引或已知脆弱版本

## 代码审查开始时，安装阶段已经结束了

最终 diff 只能回答 Agent 改了哪些仓库文件。它不会自动列出 package
manager
此前下载并执行过的代码。模型在环境配置结束后提醒包名可疑或版本存在漏洞，也无法撤回已经运行的安装脚本。

外部软件包甚至可以运行完脚本后完全不改业务源码。此时 diff
没有漏报仓库变化，只是它从来不负责记录依赖安装的执行历史。

HTTPS、签名和哈希可以帮助确认下载内容没有在途中遭到替换；lockfile
则记录已经解析出的版本，让后续安装复现同样的结果。它们保护传输和复现，却不判断最初选择的软件包、来源和版本是否正确。

如果项目配置一开始就指向攻击者控制的包，哈希可以准确核对那个包，lockfile
也可以继续复现它。安全检查必须发生在 package manager 开始安装以前。

## 先检查要安装什么，再允许安装开始

Agent 准备运行安装命令时，客户端可以先暂停，把命令里的包名、registry
和版本单独展示出来。开发者此时看到的是这次安装的实际目标，而不只是一整条难以核对的终端命令。

客户端再按项目规则核对这些信息：名称是否对应团队准备使用的软件包，registry
是否获准使用，版本是否存在已知漏洞。任何一项无法确认，安装就保持暂停，等开发者看清原因后决定是否放行。

真实项目会使用公司内部 registry、Git
依赖或本地脚本，因此这套规则不能简化成一张公共软件包清单。团队需要根据每个项目实际使用的来源和依赖形式设置例外。论文也没有测量这类规则在真实项目中的误报成本。

通过检查的依赖仍应在受限环境中安装。安装过程不接触长期凭证，网络只开放任务需要的目的地。安装前检查减少选错软件包的机会，受限环境则控制代码运行后的影响，两者解决的是不同问题。

以后再让 Coding Agent
“先把项目跑起来”，普通用户需要把它理解成一次运行第三方代码的授权。对构建
Agent 或 harness
的团队，安装前解析包名、来源和版本，遇到异常时暂停并请求批准，以及在受限环境中完成安装，都应该成为客户端的默认能力。这条安全边界属于执行层，不能只依赖模型临场判断。